arr
adalah array dari string:
["hello", "world", "stack", "overflow", "hello", "again"]
Apa cara yang mudah dan elegan untuk memeriksa apakah arr
memiliki duplikat, dan jika demikian, kembalikan salah satu dari mereka (tidak peduli yang mana)?
Contoh:
["A", "B", "C", "B", "A"] # => "A" or "B"
["A", "B", "C"] # => nil
arr == arr.uniq
akan menjadi cara yang mudah dan elegan untuk memeriksa apakaharr
memiliki duplikat, namun, itu tidak memberikan yang digandakan.Jawaban:
Saya tahu ini bukan jawaban yang sangat elegan, tetapi saya menyukainya. Kode satu liner itu indah. Dan berfungsi dengan baik kecuali Anda perlu memproses kumpulan data besar.
Mencari solusi yang lebih cepat? Ini dia!
Itu linear, O (n), tetapi sekarang perlu mengelola beberapa baris kode, perlu kasus uji, dll.
Jika Anda membutuhkan solusi yang lebih cepat, mungkin coba C sebagai gantinya.
Dan inilah intisari yang membandingkan berbagai solusi: https://gist.github.com/naveed-ahmad/8f0b926ffccf5fbd206a1cc58ce9743e
sumber
a.select {|e| a.count(e) > 1}.uniq
Anda dapat melakukan ini dalam beberapa cara, dengan opsi pertama menjadi yang tercepat:
Dan opsi O (N ^ 2) (yaitu kurang efisien):
sumber
group_by.select
ary.group_by(&:itself)
. :-)Cukup temukan contoh pertama di mana indeks objek (dihitung dari kiri) tidak sama dengan indeks objek (dihitung dari kanan).
Jika tidak ada duplikat, nilai kembali akan menjadi nol.
Saya percaya ini adalah solusi tercepat yang diposting di utas sejauh ini, juga, karena tidak bergantung pada pembuatan objek tambahan, dan
#index
dan#rindex
diimplementasikan dalam C. Runtime besar-O adalah N ^ 2 dan dengan demikian lebih lambat daripada Sergio, tetapi waktu dinding bisa lebih cepat karena fakta bahwa bagian "lambat" berjalan di C.sumber
arr.find_all {|e| arr.rindex(e) != arr.index(e) }.uniq
arr.detect.with_index { |e, idx| idx != arr.rindex(e) }
. Penggunaanwith_index
harus menghapus keharusan untukindex
pencarian pertama .detect
hanya menemukan satu duplikat.find_all
akan menemukan semuanya:sumber
count
setiap elemen dalam array. (A penghitungan hash, misalnya, jauh lebih efisien, misalnya, membangunh = {"A"=>2, "B"=>2, "C"=> 1 }
kemudianh.select { |k,v| v > 1 }.keys #=> ["A", "B"]
.Berikut adalah dua cara lain untuk menemukan duplikat.
Gunakan satu set
Gunakan
select
sebagai penggantifind
array semua duplikat.Menggunakan
Array#difference
Penurunan
.first
untuk mengembalikan larik semua duplikat.Kedua metode kembali
nil
jika tidak ada duplikat.Saya mengusulkan agar
Array#difference
ditambahkan ke inti Ruby. Informasi lebih lanjut ada dalam jawaban saya di sini .Tolok ukur
Mari kita bandingkan metode yang disarankan. Pertama, kita membutuhkan array untuk pengujian:
dan metode untuk menjalankan benchmark untuk berbagai test array:
Saya tidak memasukkan jawaban @ JjP karena hanya satu duplikat yang akan dikembalikan, dan ketika jawabannya diubah untuk melakukan itu sama dengan jawaban @ Naveed sebelumnya. Saya juga tidak memasukkan jawaban @ Marin, yang, ketika diposting sebelum jawaban @ Naveed, mengembalikan semua duplikat daripada hanya satu (titik kecil tetapi tidak ada gunanya mengevaluasi keduanya, karena mereka identik ketika mengembalikan hanya satu duplikat).
Saya juga memodifikasi jawaban lain yang mengembalikan semua duplikat untuk mengembalikan hanya yang pertama ditemukan, tetapi yang seharusnya tidak berpengaruh pada kinerja, karena mereka menghitung semua duplikat sebelum memilih satu.
Hasil untuk setiap tolok ukur terdaftar dari yang tercepat hingga yang paling lambat:
Pertama anggap array berisi 100 elemen:
Sekarang pertimbangkan sebuah array dengan 10.000 elemen:
Catatan yang
find_a_dup_using_difference(arr)
akan jauh lebih efisien jikaArray#difference
diimplementasikan dalam C, yang akan terjadi jika ditambahkan ke inti Ruby.Kesimpulan
Banyak jawaban yang masuk akal tetapi menggunakan Set adalah pilihan terbaik yang jelas . Ini tercepat dalam kasus-kasus menengah-keras, paling cepat bersama dalam yang paling sulit dan hanya dalam kasus-kasus sepele komputasi - ketika pilihan Anda tidak masalah lagi - dapat dikalahkan.
Satu kasus yang sangat istimewa di mana Anda dapat memilih solusi Chris adalah jika Anda ingin menggunakan metode ini untuk secara terpisah menduplikasi duplikat ribuan array kecil dan berharap menemukan duplikat yang biasanya kurang dari 10 item. Ini akan menjadi sedikit lebih cepat karena menghindari overhead tambahan kecil untuk membuat Set.
sumber
Sayangnya sebagian besar jawabannya adalah
O(n^2)
.Ini
O(n)
solusinya,Apa kerumitan ini?
O(n)
dan istirahat pada pertandingan pertamaO(n)
memori, tetapi hanya jumlah minimalSekarang, tergantung pada seberapa sering duplikat dalam array Anda runtime ini mungkin sebenarnya menjadi lebih baik. Sebagai contoh jika array ukuran
O(n)
telah diambil sampel dari populasik << n
elemen yang berbeda hanya kompleksitas untuk runtime dan ruang menjadiO(k)
, namun lebih mungkin bahwa poster asli memvalidasi input dan ingin memastikan tidak ada duplikat. Dalam hal ini baik runtime maupun kompleksitas memoriO(n)
karena kami memperkirakan elemen tidak memiliki pengulangan untuk sebagian besar input.sumber
Objek Ruby Array memiliki metode yang hebat
select
,.Bentuk pertama adalah minat Anda di sini. Ini memungkinkan Anda untuk memilih objek yang lulus tes.
Objek Ruby Array memiliki metode lain
count
,.Dalam hal ini, Anda tertarik pada duplikat (objek yang muncul lebih dari satu kali dalam array). Tes yang sesuai adalah
a.count(obj) > 1
.Jika
a = ["A", "B", "C", "B", "A"]
demikianAnda menyatakan bahwa Anda hanya menginginkan satu objek. Jadi pilih satu.
sumber
["A", "B", "B", "A"]
.uniq
dalam array.count
untuk setiap elemen array, yang boros dan tidak perlu. Lihat komentar saya pada jawaban JjP.find_all () mengembalikan sebuah
array
mengandung semua elemenenum
yangblock
tidakfalse
.Untuk mendapatkan
duplicate
elemenAtau
uniq
elemen rangkapsumber
Sesuatu seperti ini akan berhasil
Artinya, letakkan semua nilai ke hash di mana kunci adalah elemen array dan nilai adalah jumlah kejadian. Kemudian pilih semua elemen yang muncul lebih dari satu kali. Mudah.
sumber
Saya tahu utas ini tentang Ruby secara khusus, tetapi saya mendarat di sini mencari cara untuk melakukan ini dalam konteks Ruby on Rails dengan ActiveRecord dan berpikir saya akan membagikan solusi saya juga.
Di atas mengembalikan array semua alamat email yang digandakan dalam tabel database contoh ini (yang dalam Rails akan menjadi "active_record_classes").
sumber
Ini adalah
O(n)
prosedur.Atau Anda dapat melakukan salah satu dari baris berikut. Juga O (n) tetapi hanya satu iterasi
sumber
Inilah pendapat saya tentang kumpulan data - seperti tabel dBase lama untuk menemukan bagian duplikat
sumber
sumber
each_with_object
adalah temanmu!sumber
Kode ini akan mengembalikan daftar nilai duplikat. Kunci hash digunakan sebagai cara yang efisien untuk memeriksa nilai mana yang sudah terlihat. Berdasarkan pada apakah nilai telah terlihat, array asli
ary
dipartisi menjadi 2 array: pertama berisi nilai unik dan kedua berisi duplikat.Anda dapat memperpendeknya - meskipun dengan biaya sintaksis yang sedikit lebih kompleks - ke formulir ini:
sumber
Hasil
sumber
Jika Anda membandingkan dua array yang berbeda (bukan satu terhadap dirinya sendiri) cara yang sangat cepat adalah dengan menggunakan operator interseksi yang
&
disediakan oleh kelas Array Ruby .sumber
Saya perlu mencari tahu berapa banyak duplikat yang ada dan apa yang jadi saya menulis fungsi membangun dari apa yang diposting Naveed sebelumnya:
sumber
mari kita tunjukkan dalam Implementasi Kode
Sekarang panggil metode duplikasi dan hasil pengembalian keluaran -
sumber
[1,2,3].uniq!.nil? => true
[1,2,3,3].uniq!.nil? => false
Perhatikan hal di atas merusak
sumber