हैश रूबी को एरियर


192

ठीक है, यहाँ सौदा है, मैं इस का हल खोजने के लिए युगों से गुगली कर रहा हूँ और जब वहाँ बहुत से हैं, तो वे उस काम को करने के लिए प्रतीत नहीं होते हैं जिसकी मुझे तलाश है।

मूल रूप से मेरे पास इस तरह की एक संरचना है

["item 1", "item 2", "item 3", "item 4"] 

मैं इसे एक हैश में बदलना चाहता हूं ताकि यह इस तरह दिखे

{ "item 1" => "item 2", "item 3" => "item 4" }

यानी 'सम' इंडेक्स पर आने वाले आइटम कीज़ हैं और 'ऑड' इंडेक्स पर आइटम वैल्यूज़ हैं।

किसी भी विचार यह कैसे सफाई से करने के लिए? मुझे लगता है कि एक क्रूर बल विधि बस सभी समान अनुक्रमों को एक अलग सरणी में खींच लेगी और फिर मूल्यों को जोड़ने के लिए उनके चारों ओर लूप करेगी।

जवाबों:


357
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }

बस। *कहा जाता है सूचक ऑपरेटर।

@ माइक लेविस (टिप्पणियों में) प्रति एक चेतावनी: "इस से बहुत सावधान रहें। रूबी स्टैक पर स्प्लैंड का विस्तार करती है। यदि आप एक बड़े डेटासेट के साथ ऐसा करते हैं, तो अपने स्टैक को उड़ाने की उम्मीद करें।"

इसलिए, अधिकांश सामान्य उपयोग के मामलों के लिए यह विधि बहुत अच्छी है, लेकिन यदि आप बहुत सारे डेटा पर रूपांतरण करना चाहते हैं तो एक अलग विधि का उपयोग करें। उदाहरण के लिए, @ asukasz Niemier (टिप्पणियों में भी) बड़े डेटा सेट के लिए यह विधि प्रदान करता है:

h = Hash[a.each_slice(2).to_a]

10
@tester, *कहा जाता है सूचक ऑपरेटर। यह एक सरणी लेता है और इसे वस्तुओं की शाब्दिक सूची में परिवर्तित करता है। तो *[1,2,3,4]=> 1, 2, 3, 4। इस उदाहरण में, ऊपर करने के बराबर है Hash["item 1", "item 2", "item 3", "item 4"]। और Hashएक []विधि है जो तर्कों की एक सूची को स्वीकार करती है (यहां तक ​​कि कुंजी और विषम अनुक्रमित मानों को अनुक्रमित करती है), लेकिन Hash[]एक सरणी को स्वीकार नहीं करती है, इसलिए हम उपयोग करते हुए सरणी को अलग करते हैं *
बेन ली

15
इससे बहुत सावधान रहें। रूबी स्टैक पर स्पैट्स का विस्तार करती है। यदि आप एक बड़े डेटासेट के साथ ऐसा करते हैं, तो अपने स्टैक को उड़ाने की अपेक्षा करें।
माइक लुईस

9
बड़े डेटा टेबल पर आप उपयोग कर सकते हैं Hash[a.each_slice(2).to_a]
हौलेथ

4
"आपके स्टैक को बाहर निकालना" का क्या मतलब है?
केविन

6
@ केविन, स्टैक मेमोरी के एक छोटे से क्षेत्र का उपयोग करता है जिसे प्रोग्राम आवंटित करता है और कुछ विशिष्ट कार्यों के लिए आरक्षित करता है। आमतौर पर, यह उन विधियों का ढेर रखने के लिए उपयोग किया जाता है जिन्हें अब तक कहा जाता है। यह स्टैक ट्रेस शब्द का मूल है , और यही कारण है कि एक असीम पुनरावर्ती विधि स्टैक अतिप्रवाह का कारण बन सकती है । इस उत्तर में विधि भी स्टैक का उपयोग करती है, लेकिन चूंकि स्टैक केवल मेमोरी का एक छोटा क्षेत्र है, यदि आप इस विधि को बड़े सरणी के साथ आज़माते हैं, तो यह स्टैक को भर देगा और एक त्रुटि (उसी रेखा के साथ त्रुटि) एक ढेर अतिप्रवाह)।
बेन ली

103

रूबी 2.1.0 ने to_hएरे पर एक विधि पेश की, जो आपको जरूरी है अगर आपके मूल सरणी में कुंजी-मूल्य वाले जोड़े के सरणियाँ शामिल हैं: http://www.ruby-doc.org/core-2.1.0/Array.html#method -आई-टू_ह

[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}

1
सुंदर! यहाँ कुछ अन्य समाधानों की तुलना में बहुत बेहतर है।
डेनिस

3
पूर्व 2.1.0 माणिक संस्करणों के लिए, आप समान परिणाम प्राप्त करने के लिए Hash :: [] विधि का उपयोग कर सकते हैं, जब तक कि आपके पास नेस्टेड सरणी के जोड़े हों। so a = [[: foo,: 1], [bar, 2]] --- हैश [a] => {: foo => 1,: bar => 2}
AfDev

@AfDev, वास्तव में, धन्यवाद। आप सही हैं (जब छोटे टाइपोस को अनदेखा कर रहे हैं: barएक प्रतीक होने की आवश्यकता है, और प्रतीक :2एक पूर्णांक होना चाहिए। इसलिए, आपकी अभिव्यक्ति सही हो गई है a = [[:foo, 1], [:bar, 2]])।
जोकेम शुल्नेक्लोपर

28

बस Hash.[]सरणी में मान के साथ उपयोग करें । उदाहरण के लिए:

arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}

1
[* गिरफ्तारी] का क्या मतलब है?
एलन कोरोमेनो

1
@ मार्स: एक तर्क सूची में *arrपरिवर्तित arrहो जाता है, इसलिए यह तर्क के रूप में गिरफ्तारी []की सामग्री के साथ हैश की विधि को बुला रहा है।
चक

26

या यदि आपके पास सरणी है [key, value], तो आप कर सकते हैं:

[[1, 2], [3, 4]].inject({}) do |r, s|
  r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }

2
आप जवाब सवाल से संबंधित नहीं है और आपके मामले में यह अभी भी उसी का उपयोग करने के लिए बहुत आसान हैHash[*arr]
Yossi

2
नहीं। यह वापस आ जाएगी { [1, 2] => [3, 4] }। और चूंकि प्रश्न का शीर्षक "एश टू हैश" और बिल्ट-इन "हैश टू एरियर" विधि करता है:, { 1 => 2, 3 => 4}.to_a # => [[1, 2], [3, 4]]मैंने सोचा कि एक से अधिक लोग यहां अंतर्निर्मित "हश टू एरे" पद्धति का विलोम प्राप्त करने का प्रयास कर सकते हैं। वास्तव में, यह है कि मैं वैसे भी यहाँ कैसे समाप्त हुआ।
एरिक एस्कोडोडो

1
क्षमा करें, मैंने एक अतिरिक्त तार जोड़ा है। Hash[arr]आपके लिए काम करेंगे
योसी

9
IMHO बेहतर समाधान: हैश [* array.flatten (1)]
अतिथि

2
Yossi: मरे हुए को उठाने के लिए क्षमा करें, लेकिन उसके जवाब के साथ एक बड़ी समस्या है, और वह है #injectविधि का उपयोग। के साथ #merge!, का #each_with_objectउपयोग किया जाना चाहिए था। अगर #injectजोर दिया जाता है, #mergeबल्कि #merge!इस्तेमाल किया जाना चाहिए था।
बोरिस स्टिटनिक

12

यह वही है जिसे मैं तब खोज रहा था जब यह गुगली कर रहा था:

[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}


आप उपयोग नहीं करना चाहते हैं merge, यह एक नया हैश प्रति पाश पुनरावृत्ति बनाता है और बहुत धीमा है। यदि आपको [{a:1},{b:2}].reduce({}, :merge!)इसके बजाय हैश की एक सरणी मिली है - यह सब कुछ उसी (नए) हैश में विलय कर देता है।

धन्यवाद, यह वही है जो मैं भी चाहता था! :)
थानसिस पेटास

आप यह भी कर सकते हैं.reduce(&:merge!)
बेन ली

1
[{a: 1}, {b: 2}].reduce(&:merge!)का मूल्यांकन{:a=>1, :b=>2}
बेन ली

यह काम करता है क्योंकि इंजेक्शन / कम करने की एक विशेषता है जहां आप तर्क को छोड़ सकते हैं, इस स्थिति में यह इनपुट तर्क के रूप में संचालित करने के लिए सरणी के पहले तर्क का उपयोग करता है, और बाकी सरणी के रूप में सरणी। कि प्रतीक के साथ खरीद और आप इस संक्षिप्त निर्माण मिलता है। दूसरे शब्दों [{a: 1}, {b: 2}].reduce(&:merge!)में [{a: 1}, {b: 2}].reduce { |m, x| m.merge(x) }जो जैसा है, वैसा ही है [{b: 2}].reduce({a: 1}) { |m, x| m.merge(x) }
बेन ली

10

Enumeratorशामिल हैं Enumerable। चूंकि 2.1, Enumerableइसकी एक विधि भी है #to_h। इसीलिए, हम लिख सकते हैं: -

a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}

क्योंकि #each_sliceब्लॉक के बिना हमें देता है Enumerator, और उपरोक्त स्पष्टीकरण के अनुसार, हम ऑब्जेक्ट #to_hपर विधि को कॉल कर सकते हैं Enumerator


7

आप इस तरह की कोशिश कर सकते हैं, एकल सरणी के लिए

irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
  => ["item 1", "item 2", "item 3", "item 4"]
irb(main):020:0> Hash[*a]
  => {"item 1"=>"item 2", "item 3"=>"item 4"}

सरणी के लिए

irb(main):022:0> a = [[1, 2], [3, 4]]
  => [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
  => {1=>2, 3=>4}

6
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]

या, अगर आप नफरत करते हैं Hash[ ... ]:

a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end

या, यदि आप टूटी हुई कार्यात्मक प्रोग्रामिंग के आलसी प्रशंसक हैं:

h = a.lazy.each_slice( 2 ).tap { |a|
  break Hash.new { |h, k| h[k] = a.find { |e, _| e == k }[1] }
}
#=> {}
h["item 1"] #=> "item 2"
h["item 3"] #=> "item 4"

यदि आप पूरी तरह से नफरत नहीं करते हैं, Hash[ ... ]लेकिन इसे एक जंजीर विधि के रूप में उपयोग करना चाहते हैं (जैसे आप कर सकते हैं to_h) आप बोरिस के सुझावों को जोड़ सकते हैं और लिख सकते हैं:arr.each_slice( 2 ).map { |e| e }.tap { |a| break Hash[a] }
b- स्टूडियो

ऊपर दिए गए कोड के शब्दार्थ को स्पष्ट करने के लिए: यह एक "आलसी हैश" h बनाएगा , जो शुरू में खाली है , और जब जरूरत होगी, मूल सरणी से तत्वों को बाहर निकाल देगा। तभी वे वास्तव में ज में संग्रहीत होंगे!
डैनियल वर्नर

1

सभी उत्तर मान लेते हैं कि शुरुआती सरणी अद्वितीय है। ओपी ने निर्दिष्ट नहीं किया कि डुप्लिकेट प्रविष्टियों के साथ सरणियों को कैसे संभालना है, जिसके परिणामस्वरूप डुप्लिकेट कुंजियाँ हैं।

आइए देखें:

a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]

आप इस item 1 => item 2जोड़ी को खो देंगे क्योंकि यह ओवरराइड किया हुआ है item 1 => item 5:

Hash[*a]
=> {"item 1"=>"item 5", "item 3"=>"item 4"}

reduce(&:merge!)एक ही निष्कासन में परिणाम सहित सभी विधियाँ ।

यह हो सकता है कि यह वही है जो आप उम्मीद करते हैं, हालांकि। लेकिन अन्य मामलों में, आप शायद Arrayइसके बदले मूल्य के साथ एक परिणाम प्राप्त करना चाहते हैं :

{"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}

भोला तरीका एक सहायक चर बनाने के लिए होगा, एक हैश जिसमें एक डिफ़ॉल्ट मान है, और फिर उसे एक लूप में भरें:

result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
a.each_slice(2) {|k,v| result[k] << v }
a
=> {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}

एक पंक्ति में ऊपर का उपयोग करना assocऔर reduceकरना संभव हो सकता है , लेकिन इसके बारे में पढ़ना और पढ़ना बहुत कठिन हो जाता है।

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