Saya menggunakan Ruby 1.8.6 dengan Rails 1.2.3, dan perlu menentukan apakah dua array memiliki elemen yang sama, terlepas dari apakah urutannya sama atau tidak. Salah satu array dijamin tidak mengandung duplikat (yang lain mungkin, dalam hal ini jawabannya tidak).
Pikiran pertama saya adalah
require 'set'
a.to_set == b.to_set
tetapi saya bertanya-tanya apakah ada cara yang lebih efisien atau idiomatis untuk melakukannya.
ruby
arrays
comparison
Taymon
sumber
sumber
[1,2]
dan[2,1,1]
memiliki elemen yang sama?)difference
yang menawarkan solusi yang sangat cepat dan sangat mudah dibaca. Info selengkapnya di sini.Jawaban:
Ini tidak memerlukan konversi untuk ditetapkan:
sumber
.uniq.sort
? Selainuniq
itu mirip denganto_set
internal plus tambahan.to_a.sort
uniq
s. Sebenarnya saya akhirnya membuat salah satu array denganRange#to_a
, jadi saya hanya perlusort
yang lain.untuk dua larik A dan B: A dan B memiliki konten yang sama jika:
(A-B).blank? and (B-A).blank?
atau Anda bisa memeriksa:
((A-B) + (B-A)).blank?
Juga seperti yang disarankan oleh @ cort3z, solusi ini juga bekerja untuk array polimorfik yaitu
A = [1 , "string", [1,2,3]] B = [[1,2,3] , "string", 1] (A-B).blank? and (B-A).blank? => true # while A.uniq.sort == B.uniq.sort will throw error `ArgumentError: comparison of Fixnum with String failed`
::::::::::: EDIT :::::::::::::
Seperti yang disarankan dalam komentar, solusi di atas gagal untuk duplikat Meskipun sesuai pertanyaan yang bahkan tidak diperlukan karena penanya tidak tertarik pada duplikat (dia mengubah arraynya ke set sebelum memeriksa dan masker itu duplikat dan bahkan jika Anda melihatnya jawaban yang diterima dia menggunakan operator .uniq sebelum memeriksa dan itu juga menutupi duplikat.). Tetapi tetap saja jika duplikat menarik minat Anda, Menambahkan pemeriksaan hitungan akan memperbaikinya (sesuai pertanyaan hanya satu array yang dapat berisi duplikat). Jadi solusi akhirnya adalah:
A.size == B.size and ((A-B) + (B-A)).blank?
sumber
A=[1]
danB=[1,1]
, keduanya(A-B)
dan(B-A)
akan kembali kosong. Lihat Dokumentasi Array .a.to_set == b.to_set
dan jawaban yang diterima menggunakana.uniq.sort == b.uniq.sort
dan keduanya memberikan hasil yang sama persis seperti((A-B) + (B-A)).blank?
untuk A = [1] dan B = [1,1] setuju? Karena dia hanya meminta perbaikan atas solusi aslinya, solusi asli saya masih berfungsi :). setuju?A = [123, "test", [], some_object, nil]
danB = A#because I am lazy
, kemudianA.uniq.sort
akan membuang kesalahan (perbandingan string dan Array gagal).A = [1, 1, 2]
danB = [1, 2, 2]
Perbandingan kecepatan
require 'benchmark/ips' require 'set' a = [1, 2, 3, 4, 5, 6] b = [1, 2, 3, 4, 5, 6] Benchmark.ips do |x| x.report('sort') { a.sort == b.sort } x.report('sort!') { a.sort! == b.sort! } x.report('to_set') { a.to_set == b.to_set } x.report('minus') { ((a - b) + (b - a)).empty? } end Warming up -------------------------------------- sort 88.338k i/100ms sort! 118.207k i/100ms to_set 19.339k i/100ms minus 67.971k i/100ms Calculating ------------------------------------- sort 1.062M (± 0.9%) i/s - 5.389M in 5.075109s sort! 1.542M (± 1.2%) i/s - 7.802M in 5.061364s to_set 200.302k (± 2.1%) i/s - 1.006M in 5.022793s minus 783.106k (± 1.5%) i/s - 3.942M in 5.035311s
sumber
sort
kecepatanto_set
untuk mulai mengungguli dengan array yang cukup besar di mana O (n logn) akan mulai lebih penting daripada upaya yang diperlukan untuk mengonversi array ke setRuby 2.6+
Ruby diperkenalkan
difference
di 2.6.Ini memberikan solusi yang sangat cepat dan mudah dibaca di sini, sebagai berikut:
a = [1, 2, 3, 4, 5, 6] b = [1, 2, 3, 4, 5, 6] a.difference(b).any? # => false a.difference(b.reverse).any? # => false a = [1, 2, 3, 4, 5, 6] b = [1, 2, 3] a.difference(b).any? # => true
Menjalankan benchmark:
a = Array.new(1000) { rand(100) } b = Array.new(1000) { rand(100) } Benchmark.ips do |x| x.report('sort') { a.sort == b.sort } x.report('sort!') { a.sort! == b.sort! } x.report('to_set') { a.to_set == b.to_set } x.report('minus') { ((a - b) + (b - a)).empty? } x.report('difference') { a.difference(b).any? } end sort 13.908k (± 2.6%) i/s - 69.513k in 5.001443s sort! 14.656k (± 3.0%) i/s - 73.736k in 5.035744s to_set 5.125k (± 2.9%) i/s - 26.023k in 5.082083s minus 16.398k (± 2.2%) i/s - 83.181k in 5.074938s difference 27.839k (± 5.2%) i/s - 141.048k in 5.080706s
Semoga itu bisa membantu seseorang!
sumber
Ketika elemen dari
a
danb
adalahComparable
,Koreksi jawaban @ mori berdasarkan komentar @ steenslag
sumber
a
danb
dapat diurutkan.Jika Anda berharap
[:a, :b] != [:a, :a, :b]
to_set
tidak berhasil. Anda dapat menggunakan frekuensi sebagai gantinya:class Array def frequency p = Hash.new(0) each{ |v| p[v] += 1 } p end end [:a, :b].frequency == [:a, :a, :b].frequency #=> false [:a, :b].frequency == [:b, :a].frequency #=> true
sumber
a.sort == b.sort
jika dia peduli dengan frekuensi?["", :b].frequency == [:b, ""].frequency #=> true
a.group_by{|i| i} == b.group_by{|i| i}
Jika Anda mengetahui bahwa array memiliki panjang yang sama dan tidak ada array yang berisi duplikat maka ini juga berfungsi:
Penjelasan: yang
&
operator dalam hal ini mengembalikan salinan sans a1 setiap item tidak ditemukan dalam a2, yang sama dengan a1 asli IFF kedua array memiliki isi yang sama dengan tidak ada duplikat.Analisis: Mengingat bahwa urutannya tidak berubah, saya menduga ini diterapkan sebagai iterasi ganda secara konsisten
O(n*n)
, terutama lebih buruk untuk array besar daripadaa1.sort == a2.sort
yang seharusnya bekerja dengan kasus terburukO(n*logn)
.sumber
a1 = [1,2,3], a2 = [2, 1, 3]
a1 && a2
pengembalian[2,1,3]
untuk saya yang tidak sama dengana1
a1==a2
? Ini dapat berfungsi jikaarray1
di sisi kanan persamaan diganti oleharray2
, tetapi saya ragu bahwa urutan elemen yang dikembalikan oleh&
dijamin.&
adalah operator persimpangan set untuk array,&&
logis DAN - mereka sangat berbeda!menggabungkan
&
dansize
mungkin juga cepat.require 'benchmark/ips' require 'set' Benchmark.ips do |x| x.report('sort') { a.sort == b.sort } x.report('sort!') { a.sort! == b.sort! } x.report('to_set') { a.to_set == b.to_set } x.report('minus') { ((a - b) + (b - a)).empty? } x.report('&.size') { a.size == b.size && (a & b).size == a.size } end Calculating ------------------------------------- sort 896.094k (±11.4%) i/s - 4.458M in 5.056163s sort! 1.237M (± 4.5%) i/s - 6.261M in 5.071796s to_set 224.564k (± 6.3%) i/s - 1.132M in 5.064753s minus 2.230M (± 7.0%) i/s - 11.171M in 5.038655s &.size 2.829M (± 5.4%) i/s - 14.125M in 5.010414s
sumber
Salah satu pendekatannya adalah mengulang array tanpa duplikat
# assume array a has no duplicates and you want to compare to b !a.map { |n| b.include?(n) }.include?(false)
Ini mengembalikan larik trues. Jika salah muncul, maka bagian luar
include?
akan mengembalikan nilai benar. Jadi, Anda harus membalik semuanya untuk menentukan apakah itu cocok.sumber