2008-10-08 8 views
24

मेरे पास हैश की एक सरणी है, और मैं इसके अद्वितीय मूल्य चाहता हूं। कॉलिंग Array.uniq मुझे वह नहीं देता जो मुझे उम्मीद है।रूबी में हैश की सरणी से अद्वितीय तत्व कैसे प्राप्त करूं?

a = [{:a => 1},{:a => 2}, {:a => 1}] 
a.uniq # => [{:a => 1}, {:a => 2}, {:a => 1}] 

मैं कहाँ की उम्मीद:

[{:a => 1}, {:a => 2}] 

नेट पर चारों ओर खोज में, मैं एक समाधान है कि मैं के साथ खुश था के साथ नहीं आया था। लोगों ने Hash.eql? और Hash.hash को फिर से परिभाषित करने की अनुशंसा की, क्योंकि Array.uniq यह पूछताछ कर रहा है।

संपादित करें: कहाँ मैं असली दुनिया में इस में भाग गया, हैश थोड़ा और अधिक जटिल थे। वे पार्स किए गए JSON का परिणाम थे जिनमें कई फ़ील्ड थे, जिनमें से कुछ मूल्य भी हैं। मेरे पास उन परिणामों का एक सरणी था जो मैं अद्वितीय मूल्यों को फ़िल्टर करना चाहता था।

मैं, फिर से परिभाषित Hash.eql? और Hash.hash समाधान पसंद नहीं है, क्योंकि मैं या तो विश्व स्तर पर Hash को फिर से परिभाषित करने के लिए होगा, या मेरे सरणी में प्रत्येक प्रविष्टि के लिए यह फिर से परिभाषित। प्रत्येक प्रविष्टि के लिए Hash की परिभाषा को बदलना बोझिल होगा, खासकर जब प्रत्येक प्रविष्टि के अंदर नेस्टेड हैश हो सकता है।

बदलने Hash विश्व स्तर पर, कुछ की क्षमता है, खासकर अगर यह अस्थायी रूप से किया गया था। मैं एक और कक्षा या सहायक समारोह बनाना चाहता हूं जो पुराने परिभाषाओं को सहेजने और उन्हें बहाल करने के लिए लपेटा गया है, लेकिन मुझे लगता है कि यह वास्तव में आवश्यकतानुसार अधिक जटिलता जोड़ता है।

inject का उपयोग Hash को फिर से परिभाषित करने के लिए एक अच्छा विकल्प लगता है।

उत्तर

27

मैं बुला inject

a = [{:a => 1},{:a => 2}, {:a => 1}] 
a.inject([]) { |result,h| result << h unless result.include?(h); result } 

यह वापस आ जाएगी द्वारा जो मैं चाहता प्राप्त कर सकते हैं:

[{:a=>1}, {:a=>2}] 
+0

और अधिक बेहतर मैं एक लिंक मैं – edthix

0

उत्तर देंगे, उससे इसी तरह की है करने के लिए एक here पर चर्चा की। यह को सही ढंग से व्यवहार करने वाले सरणी में दिखाई देने वाले हैंश पर hash और eql? विधियों को ओवरराइड करता है।

+0

समाधान मैं नेट पर पाया में से एक है कि इसके बाद के संस्करण तैनात की तुलना में लगता है। मुझे यह पसंद नहीं आया कि मुझे हेश को फिर से परिभाषित करने की जरूरत है, बस यूनिक को कॉल करने के लिए। –

+0

यदि वेनिला हैश और ऐरे कक्षाएं आपको जो चाहिए वह नहीं करती हैं तो आपको वास्तव में आवश्यक कक्षाओं को लागू करने वाले अपने वर्गों को परिभाषित करने पर विचार करना चाहिए। क्या आप वर्णन कर सकते हैं कि आप हैश के सरणी के साथ मॉडल करने की कोशिश कर रहे हैं? –

2

मानते हुए अपने हैश हमेशा एक कुंजी-मान जोड़ों कर रहे हैं, यह काम करेगा:

a.map {|h| h.to_a[0]}.uniq.map {|k,v| {k => v}} 

Hash.to_a मुख्य मान सरणियों की एक सरणी बनाता है, इसलिए पहले नक्शा आप हो जाता है:

[[:a, 1], [:a, 2], [:a, 1]] 
पर सरणी

uniq आप क्या चाहते हैं करता है, आप दे रही है:

[[:a, 1], [:a, 2]] 

और फिर दूसरी नक्शा उन्हें वापस डालता है एक साथ फिर से हैश के रूप में एर।

+0

वास्तविक दुनिया की समस्या जो मैंने पार की थी, अधिक जटिल हैश का उपयोग किया। –

+0

यह सुनिश्चित नहीं है कि यह क्यों मतदान किया गया था, इसलिए मैंने इसे वापस रखा। –

5

मैं एक ऐसी ही स्थिति लिया है गया है लेकिन यह हैश कुंजी थी। मैंने सॉर्टिंग विधि का इस्तेमाल किया।

मैं क्या मतलब:

आप एक सरणी है:

[{:x=>1},{:x=>2},{:x=>3},{:x=>2},{:x=>1}] 

आप इसे (#sort_by {|t| t[:x]}) सॉर्ट और यह मिलता है:

[{:x=>1}, {:x=>1}, {:x=>2}, {:x=>2}, {:x=>3}] 
अब

Aaaron से जवाब का एक सा संशोधित संस्करण हिनी:

your_array.inject([]) do |result,item| 
    result << item if !result.last||result.last[:x]!=item[:x] 
    result 
end 

मैं भी कोशिश की है:

test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]} 

लेकिन यह बहुत धीमी है।

test=[] 
1000.times {test<<{:x=>rand}} 

Benchmark.bmbm do |bm| 
    bm.report("sorting: ") do 
    test.sort_by {|t| t[:x]}.inject([]) {|r,h| r<<h if !r.last||r.last[:x]!=h[:x]; r} 
    end 
    bm.report("inject: ") {test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]} } 
end 

परिणाम::

Rehearsal --------------------------------------------- 
sorting: 0.010000 0.000000 0.010000 ( 0.005633) 
inject:  0.470000 0.140000 0.610000 ( 0.621973) 
------------------------------------ total: 0.620000sec 

       user  system  total  real 
sorting: 0.010000 0.000000 0.010000 ( 0.003839) 
inject:  0.480000 0.130000 0.610000 ( 0.612438) 
17

रूबी 1.8.7+ सिर्फ वापसी क्या आप उम्मीद करेंगे:

[{:a=>1}, {:a=>2}, {:a=>1}].uniq 
#=> [{:a=>1}, {:a=>2}] 
0

सरणियों पर पाइप विधि (1.8 के बाद से उपलब्ध यहाँ मेरी बेंचमार्क है .6) सेट यूनियन (एक सरणी लौट रहा है) करता है, इसलिए निम्न किसी भी सरणी a:

के अद्वितीय तत्व प्राप्त करने का एक और संभावित तरीका है

[] | a

+0

यह मेरे लिए काम नहीं करता है। –

+0

@ सुनीरगुप्ता, रूबी का आप किस संस्करण का उपयोग कर रहे हैं? – yoniLavi

+0

'रूबी 1.9.3 पी 448 (2013-06-27 संशोधन 41675) [x86_64-darwin13.2.0]' –

1

आप उपयोग कर सकते हैं (रूबी 1.9.3 में परीक्षण),

[{a: 1},{a: 2},{a:1}].uniq => [{a:1},{a: 2}] 
[{a: 1,b: 2},{a: 2, b: 2},{a: 1, b: 3}].uniq_by {|v| v[:a]} => [{a: 1,b: 2},{a: 2, b: 2}] 
संबंधित मुद्दे