जांचें कि क्या दो सरणियों में समान सामग्री है (किसी भी क्रम में)


90

मैं रूबी 1.8.6 का उपयोग रेल 1.2.3 के साथ कर रहा हूं, और यह निर्धारित करने की आवश्यकता है कि क्या दो सरणियों में समान तत्व हैं, चाहे वे एक ही क्रम में हों या नहीं। सरणियों में से एक को डुप्लिकेट (अन्य का जवाब नहीं है, जिस स्थिति में उत्तर नहीं है) को शामिल नहीं करने की गारंटी है।

मेरा पहला विचार था

require 'set'
a.to_set == b.to_set

लेकिन मैं सोच रहा था कि क्या ऐसा करने का एक अधिक कुशल या मुहावरेदार तरीका था।



Array.should प्रयास करें = ~ another_array जांच stackoverflow.com/questions/2978922/...
एथेना

आप बहुत से भ्रम को बचा सकते थे: 1) यह बताते हुए कि क्या सरणियों के तत्व आवश्यक रूप से छंटनी वाले हैं; और 2) एक सरल उदाहरण प्रदान करें कि आप क्या मतलब है, "क्या दो सरणियों में एक ही तत्व हैं" (उदाहरण के लिए, [1,2]और [2,1,1]एक ही तत्व हैं?)
कैरी स्वेवेलैंड

रूबी 2.6 पेश किया है differenceजो बहुत तेज और बहुत पठनीय दोनों का समाधान प्रदान करता है। अधिक जानकारी यहाँ।
SRack

जवाबों:


140

इसे सेट करने के लिए रूपांतरण की आवश्यकता नहीं है:

a.sort == b.sort

कोई रूपांतरण नहीं? .uniq.sortफिर क्या है ? इसके अलावा आंतरिक रूप से अतिरिक्त के uniqसमान हैto_set.to_a.sort
विक्टर मोरोज़

इसे स्वीकार करने के बाद से मैं इसके उपयोग के करीब हूं, हालांकि एस के बिना uniq। वास्तव में मैंने एक के साथ एक सरणियों का निर्माण किया Range#to_a, इसलिए मेरे पास केवल sortदूसरे के लिए था ।
तैमून

11
यह काम नहीं करेगा यदि सरणी में ऐसे तत्व हैं जो केवल हल नहीं किए जा सकते हैं (उदाहरण के लिए हैश की एक सरणी)। साहिल धनखड़ का समाधान अधिक सामान्य समाधान प्रतीत होता है।
ब्रैड

40

दो सरणियों ए और बी के लिए: ए और बी में एक ही सामग्री है यदि: (A-B).blank? and (B-A).blank?

या आप बस इसके लिए जाँच कर सकते हैं: ((A-B) + (B-A)).blank?

जैसा कि @ cort3z द्वारा सुझाया गया है यह समाधान als0 बहुरूपी सरणियों के लिए काम करता है

 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 :::::::::::::

जैसा कि टिप्पणियों में सुझाव दिया गया है, उपरोक्त समाधान डुप्लिकेट के लिए विफल रहता है। हालांकि सवाल के अनुसार भी आवश्यक नहीं है, क्योंकि पूछने वाले को डुप्लिकेट में कोई दिलचस्पी नहीं है (वह चेक करने से पहले सेट करने के लिए अपने सरणियों को परिवर्तित कर रहा है और वह नकल करता है और भले ही आप देखें जवाब देने से पहले वह एक .unq ऑपरेटर का उपयोग कर रहा है और वह भी नकल करता है।)। लेकिन फिर भी अगर आपकी रुचि डुप्लिकेट है, तो बस गिनती की जांच को जोड़ने से एक ही तय हो जाएगा (प्रश्न के अनुसार केवल एक सरणी में डुप्लिकेट हो सकते हैं)। तो अंतिम समाधान होगा: A.size == B.size and ((A-B) + (B-A)).blank?


यह विफल हो जाएगा यदि या तो सरणी में डुप्लिकेट हैं। उदाहरण के लिए, अगर A=[1]और B=[1,1], दोनों (A-B)और (B-A)खाली वापस आ जाएगी। सरणी दस्तावेज़ देखें ।
jtpereyda

@dafrazzman आपसे पूरी तरह सहमत हैं। मैंने आपकी प्रतिक्रिया को शामिल करने के लिए अपने उत्तर को संशोधित कर दिया है। लेकिन यदि आपके पास प्रश्न (या स्वीकृत उत्तर) पर करीबी नज़र है, तो पूछने वाला उपयोग कर रहा है: a.to_set == b.to_set और स्वीकृत उत्तर का उपयोग कर रहा है a.uniq.sort == b.uniq.sortऔर दोनों ((A-B) + (B-A)).blank?A = [1] के समान सटीक परिणाम देते हैं। और बी = [११ ९] सहमत हैं? चूंकि वह सिर्फ अपने मूल समाधान पर सुधार के लिए पूछ रहा था, मेरा मूल समाधान अभी भी काम करता है :)। इस बात से सहमत?
साहिल धनखड़

1
यह समाधान काफी अच्छा है क्योंकि यह कई प्रकार की वस्तुओं को संभालता है। कहते हैं कि आपके पास है A = [123, "test", [], some_object, nil]और B = A#because I am lazyफिर A.uniq.sortत्रुटि (स्ट्रिंग और ऐरे की तुलना में विफल) फेंक देंगे।
ऑटोमैटिक

क्या यह O (n) होगा, क्योंकि यह सरणी आकार पर निर्भर है? (रैखिक)
user3007294

1
यह काम नहीं करेगा यदि सरणियों का आकार समान हो लेकिन दोहराया तत्व समान नहीं हैं। उदाहरण के लिए A = [1, 1, 2]औरB = [1, 2, 2]
बौडी

23

गति की बाध्यता

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

btw elemetns के आदेश को प्रभावित नहीं करता sortहै गति
मोरोज़ोव

मुझे आश्चर्य हुआ ... मुझे उम्मीद है कि सेट ओ लुकिंग (एन) समय की जटिलता के कारण सभी दूसरों से बेहतर प्रदर्शन करेंगे। ताकि किसी भी अच्छी तरह से लागू किए गए सॉर्ट में ओ (एन लोगन) की आवश्यकता हो। जबकि सेट करने और मूल्यों को देखने के लिए कास्टिंग कुल मिलाकर इसे ओ (एन) समय में कर देगा।
ओलेग अफ़ानसेव

1
मैं to_setबड़े पर्याप्त सरणियों के साथ बेहतर प्रदर्शन शुरू करने की उम्मीद करूंगा जहां ओ (एन लोगन) सेट करने के लिए सरणी को परिवर्तित करने के लिए आवश्यक प्रयास से अधिक
मायने रखना

1
यह मददगार है, लेकिन वास्तव में अपने आप में एक जवाब नहीं है? शायद एक मौजूदा समाधान में इसे जोड़ना बेहतर है?
SRack

19

रूबी 2.6+

रूबी ने difference2.6 में पेश किया।

यह एक बहुत तेज, बहुत पठनीय समाधान यहाँ देता है, इस प्रकार है:

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

बेंचमार्क चलाना:

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

आशा है कि किसी की मदद करता है!


4
अंतर इस मामले में टूट रहा है a = [1, 2, 3] b = [1, 2, 3, 4, 5] a.difference (b) .any? => असत्य
त्रुटि ४०४ '


8

यदि आप उम्मीद करते हैं कि [:a, :b] != [:a, :a, :b] to_setकाम नहीं करेगा। आप इसके बजाय आवृत्ति का उपयोग कर सकते हैं:

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

क्यों नहीं a.sort == b.sortअगर वह आवृत्ति के बारे में परवाह है?
fl00r

4
@ fl00r यदि आइटम तुलनीय नहीं हैं तो क्या होगा? ["", :b].frequency == [:b, ""].frequency #=> true
विक्टर मोरोज

2
यह भी आप के रूप में कुछ कार्यात्मक कर सकते हैंa.group_by{|i| i} == b.group_by{|i| i}
fl00r

7

यदि आप जानते हैं कि सरणियाँ समान लंबाई की हैं और न ही सरणी में डुप्लिकेट हैं तो यह भी काम करता है:

( array1 & array2 ) == array1

स्पष्टीकरण:& इस मामले में ऑपरेटर a1 बिना की एक प्रति किसी भी आइटम a2 में नहीं मिला है, जो मूल a1 रूप में ही है iff दोनों सरणियों कोई डुप्लिकेट के साथ एक ही सामग्री है देता है।

विश्लेषण: यह देखते हुए कि आदेश अपरिवर्तित है, मुझे लगता है कि यह एक दोहरे पुनरावृत्ति के रूप में कार्यान्वित किया जाता है लगातार O(n*n), विशेष रूप से अन्य सरणियों के लिए इससे भी बदतरa1.sort == a2.sort जो सबसे खराब स्थिति के साथ प्रदर्शन करना चाहिए O(n*logn)


2
हमेशा काम नहीं करता है: मेरे लिए a1 = [1,2,3], a2 = [2, 1, 3] a1 && a2रिटर्न [2,1,3]जो बराबर नहीं हैa1
कल्याण रघु

@ काइलान, क्या इसका मतलब यह नहीं है कि यह केवल कब काम करता है a1==a2? यह काम कर सकता है यदि array1समानता के दाईं ओर से प्रतिस्थापित किया जाता है array2, लेकिन मुझे संदेह है कि तत्वों द्वारा लौटाए गए आदेश की &गारंटी है।
कैरी सोवेलैंड

1
@KalyanRaghu &सरणियों के लिए एक सेट चौराहे ऑपरेटर है, &&तार्किक है और वे बहुत अलग हैं!
किमबॉल

3

संयोजन &और sizeतेजी से भी हो सकता है।

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

2

एक दृष्टिकोण डुप्लिकेट के साथ सरणी पर पुनरावृति करना है

# assume array a has no duplicates and you want to compare to b
!a.map { |n| b.include?(n) }.include?(false)

यह trues की एक सरणी देता है। अगर कोई झूठा दिखाई पड़ता है, तो बाहरी include?सच लौट आएगा। इस प्रकार आपको यह निर्धारित करने के लिए कि क्या यह एक मैच है, पूरी तरह से पलटना होगा।


@ विक्टर मोरोज़, आप सही हैं, और एक आवृत्ति गिनती बस ओ (एन) होगी।
रॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.