रूबी में, निम्न रूपों में से एक में एक सरणी दी ...
[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]
... इसे हैश के रूप में रूपांतरित करने का सबसे अच्छा तरीका क्या है ...
{apple => 1, banana => 2}
रूबी में, निम्न रूपों में से एक में एक सरणी दी ...
[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]
... इसे हैश के रूप में रूपांतरित करने का सबसे अच्छा तरीका क्या है ...
{apple => 1, banana => 2}
जवाबों:
नोट : एक संक्षिप्त और कुशल समाधान के लिए, नीचे मार्क-एंड्रे लाफ्यून का जवाब देखें।
यह जवाब मूल रूप से सपाट का उपयोग करने के लिए एक विकल्प के रूप में पेश किया गया था, जो कि लेखन के समय सबसे उच्च उत्थान थे। मुझे स्पष्ट करना चाहिए कि मैं इस उदाहरण को एक सर्वोत्तम अभ्यास या एक कुशल दृष्टिकोण के रूप में प्रस्तुत करना नहीं चाहता था। मूल उत्तर इस प्रकार है।
चेतावनी! समतल का उपयोग करने वाले समाधान एरे कीज या मान को संरक्षित नहीं करेंगे!
@ जॉन टॉपले के लोकप्रिय उत्तर पर, आइए कोशिश करें:
a3 = [ ['apple', 1], ['banana', 2], [['orange','seedless'], 3] ]
h3 = Hash[*a3.flatten]
यह एक त्रुटि फेंकता है:
ArgumentError: odd number of arguments for Hash
from (irb):10:in `[]'
from (irb):10
कंस्ट्रक्टर एक समान लंबाई (जैसे ['k1', 'v1,' k2 ',' v2 ']) के एक ऐरे की उम्मीद कर रहा था। इससे भी बुरी बात यह है कि एक अलग ऐरे जो एक समान लंबाई तक चपटा होता है, वह चुपचाप हमें गलत मूल्यों के साथ एक हश देता है।
यदि आप सरणी कुंजी या मान का उपयोग करना चाहते हैं, तो आप मानचित्र का उपयोग कर सकते हैं :
h3 = Hash[a3.map {|key, value| [key, value]}]
puts "h3: #{h3.inspect}"
यह ऐरे कुंजी को सुरक्षित रखता है:
h3: {["orange", "seedless"]=>3, "apple"=>1, "banana"=>2}
h3 = Hash[*a3.flatten(1)]
इसके बजाय h3 = Hash[*a3.flatten]
एक त्रुटि फेंक देंगे।
to_h
बेहतर है।
बस उपयोग करें Hash[*array_variable.flatten]
उदाहरण के लिए:
a1 = ['apple', 1, 'banana', 2]
h1 = Hash[*a1.flatten(1)]
puts "h1: #{h1.inspect}"
a2 = [['apple', 1], ['banana', 2]]
h2 = Hash[*a2.flatten(1)]
puts "h2: #{h2.inspect}"
Array#flatten(1)
सीमा का उपयोग करते हुए पुनरावृत्ति होती है इसलिए Array
कुंजी और मान अपेक्षित रूप से काम करते हैं।
Hash[*ary.flatten(1)]
, जो सरणी कुंजियों और मूल्यों को संरक्षित करेगा। यह पुनरावर्ती flatten
है जो उन्हें नष्ट कर रहा है, जो बचने के लिए काफी आसान है।
उपयोग करने का सबसे अच्छा तरीका है Array#to_h
:
[ [:apple,1],[:banana,2] ].to_h #=> {apple: 1, banana: 2}
ध्यान दें कि to_h
एक ब्लॉक को भी स्वीकार करता है:
[:apple, :banana].to_h { |fruit| [fruit, "I like #{fruit}s"] }
# => {apple: "I like apples", banana: "I like bananas"}
नोट : to_h
रूबी 2.6.0+ में एक ब्लॉक स्वीकार करता है; जल्दी माणिक के लिए आप मेरे backports
मणि का उपयोग कर सकते हैं औरrequire 'backports/2.6.0/enumerable/to_h'
to_h
बिना ब्लॉक रूबी 2.1.0 में पेश किया गया था।
रूबी 2.1 से पहले, कोई कम सुपाठ्य का उपयोग कर सकता है Hash[]
:
array = [ [:apple,1],[:banana,2] ]
Hash[ array ] #= > {:apple => 1, :banana => 2}
अंत में, किसी भी समाधान का उपयोग करने से सावधान रहें, इससे उन flatten
मानों के साथ समस्याएं पैदा हो सकती हैं जो स्वयं सरणियां हैं।
to_h
उपरोक्त उत्तरों से बेहतर विधि पसंद है क्योंकि यह सरणी पर संचालित होने के बाद परिवर्तित करने के इरादे को व्यक्त करता है ।
Array#to_h
है और न ही Enumerable#to_h
कोर रूबी 1.9 में है।
[[apple, 1], [banana, 2], [apple, 3], [banana, 4]]
और मुझे आउटपुट के रूप में चाहिए {"apple" =>[1,3], "banana"=>[2,4]}
?
अपडेट करें
रूबी 2.1.0 आज जारी किया गया है । और मैं Array#to_h
( रिलीज नोट्स और रूबी-डॉक ) के साथ आता हूं , जो Array
कि ए को कन्वर्ट करने के मुद्दे को हल करता है Hash
।
रूबी डॉक्स उदाहरण:
[[:foo, :bar], [1, 2]].to_h # => {:foo => :bar, 1 => 2}
संपादित करें: जब मैं लिख रहा था, तब पोस्ट की गई प्रतिक्रियाएं, हैश [a.flatten] जाने का रास्ता लगती हैं। जब मैं प्रतिक्रिया के माध्यम से सोच रहा था तो दस्तावेज में उस बिट को याद किया जाना चाहिए। सोचा था कि जो समाधान मैंने लिखा है, यदि आवश्यक हो तो विकल्प के रूप में इस्तेमाल किया जा सकता है।
दूसरा रूप सरल है:
a = [[:apple, 1], [:banana, 2]]
h = a.inject({}) { |r, i| r[i.first] = i.last; r }
ए = सरणी, एच = हैश, आर = रिटर्न-वैल्यू हैश (हम जिसे जमा करते हैं), मैं = सरणी में आइटम
सबसे आसान तरीका है कि मैं पहली बार ऐसा करने के बारे में सोच सकता हूं:
a = [:apple, 1, :banana, 2]
h = {}
a.each_slice(2) { |i| h[i.first] = i.last }
a.inject({})
एक-लाइनर के लिए +1 जो अधिक लचीले मूल्य असाइनमेंट की अनुमति देता है।
h = {}
, सुई के उपयोग के माध्यम से दूसरे उदाहरण से साथ समाप्तa.each_slice(2).inject({}) { |h,i| h[i.first] = i.last; h }
a.each_slice(2).to_h
यह उत्तर अन्य उत्तरों से सूचना के व्यापक लपेटे जाने की उम्मीद करता है।
बहुत छोटा संस्करण, प्रश्न से डेटा दिया और साथ ही कुछ अतिरिक्त:
flat_array = [ apple, 1, banana, 2 ] # count=4
nested_array = [ [apple, 1], [banana, 2] ] # count=2 of count=2 k,v arrays
incomplete_f = [ apple, 1, banana ] # count=3 - missing last value
incomplete_n = [ [apple, 1], [banana ] ] # count=2 of either k or k,v arrays
# there's one option for flat_array:
h1 = Hash[*flat_array] # => {apple=>1, banana=>2}
# two options for nested_array:
h2a = nested_array.to_h # since ruby 2.1.0 => {apple=>1, banana=>2}
h2b = Hash[nested_array] # => {apple=>1, banana=>2}
# ok if *only* the last value is missing:
h3 = Hash[incomplete_f.each_slice(2).to_a] # => {apple=>1, banana=>nil}
# always ok for k without v in nested array:
h4 = Hash[incomplete_n] # or .to_h => {apple=>1, banana=>nil}
# as one might expect:
h1 == h2a # => true
h1 == h2b # => true
h1 == h3 # => false
h3 == h4 # => true
चर्चा और विवरण का पालन करें।
हम जो डेटा सामने दिखा रहे हैं, उसे दिखाने के लिए, मैं डेटा के लिए विभिन्न संभावनाओं का प्रतिनिधित्व करने के लिए कुछ चर बनाऊंगा। वे निम्नलिखित श्रेणियों में फिट होते हैं:
a1
और a2
:(नोट: मुझे लगता है कि apple
और banana
वेरिएबल्स का प्रतिनिधित्व करने के लिए थे। जैसा कि दूसरों ने किया है, मैं यहां से तार का उपयोग करूंगा ताकि इनपुट और परिणाम मेल खा सकें।)
a1 = [ 'apple', 1 , 'banana', 2 ] # flat input
a2 = [ ['apple', 1], ['banana', 2] ] # key/value paired input
a3
:कुछ अन्य उत्तरों में, एक और संभावना प्रस्तुत की गई थी (जो मैं यहां पर विस्तार करता हूं) - चाबियाँ और / या मान अपने स्वयं के एरियर्स हो सकते हैं:
a3 = [ [ 'apple', 1 ],
[ 'banana', 2 ],
[ ['orange','seedless'], 3 ],
[ 'pear', [4, 5] ],
]
a4
:अच्छे उपाय के लिए, मुझे लगा कि मैं एक ऐसे मामले के लिए जोड़ूंगा जहां हमारे पास एक अधूरा इनपुट हो सकता है:
a4 = [ [ 'apple', 1],
[ 'banana', 2],
[ ['orange','seedless'], 3],
[ 'durian' ], # a spiky fruit pricks us: no value!
]
a1
:कुछ ने उपयोग करने का सुझाव दिया है #to_h
(जो कि रूबी 2.1.0 में दिखाया गया है, और इसे पहले के संस्करणों में वापस लाया जा सकता है )। प्रारंभिक-सपाट सरणी के लिए, यह काम नहीं करता है:
a1.to_h # => TypeError: wrong element type String at 0 (expected array)
स्पैट ऑपरेटरHash::[]
के साथ संयुक्त का उपयोग करता है:
Hash[*a1] # => {"apple"=>1, "banana"=>2}
तो उस सरल मामले के लिए इसका प्रतिनिधित्व द्वारा समाधान है a1
।
a2
:[key,value]
प्रकार सरणियों की एक सरणी के साथ , जाने के दो तरीके हैं।
सबसे पहले, Hash::[]
अभी भी काम करता है (जैसा कि उसने किया था *a1
):
Hash[a2] # => {"apple"=>1, "banana"=>2}
और फिर #to_h
अब भी काम करता है:
a2.to_h # => {"apple"=>1, "banana"=>2}
तो, सरल नेस्टेड सरणी मामले के लिए दो आसान उत्तर।
a3
:Hash[a3] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "pear"=>[4, 5]}
a3.to_h # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "pear"=>[4, 5]}
यदि हमें इनपुट डेटा मिला है जो संतुलित नहीं है, तो हम इसके साथ समस्याओं में चलेंगे #to_h
:
a4.to_h # => ArgumentError: wrong array length at 3 (expected 2, was 1)
लेकिन फिर Hash::[]
भी काम करता है, बस a4 के nil
लिए मान के रूप में सेटिंग durian
(और किसी भी अन्य सरणी तत्व है कि सिर्फ एक 1-मूल्य सरणी है):
Hash[a4] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "durian"=>nil}
a5
औरa6
एक तर्क के flatten
साथ या उसके बिना वर्णित कुछ अन्य उत्तर 1
, तो चलिए कुछ नए चर बनाते हैं:
a5 = a4.flatten
# => ["apple", 1, "banana", 2, "orange", "seedless" , 3, "durian"]
a6 = a4.flatten(1)
# => ["apple", 1, "banana", 2, ["orange", "seedless"], 3, "durian"]
मैंने a4
संतुलन की समस्या के कारण आधार डेटा के रूप में उपयोग करने के लिए चुना , जो हमारे पास था a4.to_h
। मुझे लगता है कि कॉलिंग flatten
एक दृष्टिकोण हो सकता है जिसका उपयोग करने के लिए कोई व्यक्ति इसका उपयोग करने की कोशिश कर सकता है, जो निम्नलिखित की तरह लग सकता है।
flatten
बिना तर्क ( a5
):Hash[*a5] # => {"apple"=>1, "banana"=>2, "orange"=>"seedless", 3=>"durian"}
# (This is the same as calling `Hash[*a4.flatten]`.)
भोली नज़र में, यह काम करने के लिए प्रकट होता है - लेकिन यह हमें बीजहीन संतरे के साथ गलत पैर पर मिल गया, इस प्रकार 3
एक कुंजी और durian
एक मूल्य भी बना ।
और यह, जैसा कि a1
, बस काम नहीं करता है:
a5.to_h # => TypeError: wrong element type String at 0 (expected array)
तो a4.flatten
हमारे लिए उपयोगी नहीं है, हम सिर्फ उपयोग करना चाहते हैंHash[a4]
flatten(1)
मामले ( a6
):लेकिन केवल आंशिक रूप से चपटे होने के बारे में क्या? यह ध्यान देने योग्य बात है कि फोन करने के लायक Hash::[]
का उपयोग कर splat
आंशिक रूप से चपटा सरणी (पर a6
) है नहीं कॉल करने जैसा ही Hash[a4]
:
Hash[*a6] # => ArgumentError: odd number of arguments for Hash
a6
):लेकिन क्या होगा अगर इस तरह से हम पहली जगह में सरणी प्राप्त करेंगे? (अर्थात, तुलनात्मक रूप से a1
, यह हमारा इनपुट डेटा था - बस इस बार कुछ डेटा एरेज़ या अन्य ऑब्जेक्ट हो सकते हैं।) हमने देखा है कि Hash[*a6]
यह काम नहीं करता है, लेकिन क्या होगा अगर हम अभी भी व्यवहार प्राप्त करना चाहते हैं। अंतिम तत्व (महत्वपूर्ण! नीचे देखें) एक nil
मूल्य के लिए एक कुंजी के रूप में काम करता है ?
ऐसी स्थिति में, ऐसा करने का एक तरीका अभी भी है, बाहरी सरणी में तत्वों के रूप में Enumerable#each_slice
अपने आप को कुंजी / मान जोड़े में वापस लाने के लिए उपयोग करना :
a7 = a6.each_slice(2).to_a
# => [["apple", 1], ["banana", 2], [["orange", "seedless"], 3], ["durian"]]
ध्यान दें कि इससे हमें एक नया सरणी मिल रहा है जो " समान " नहीं है a4
, लेकिन इसमें समान मान हैं :
a4.equal?(a7) # => false
a4 == a7 # => true
और इस प्रकार हम फिर से उपयोग कर सकते हैं Hash::[]
:
Hash[a7] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "durian"=>nil}
# or Hash[a6.each_slice(2).to_a]
यह ध्यान रखना महत्वपूर्ण है कि each_slice(2)
समाधान केवल चीजों को वापस पवित्रता में लाता है यदि अंतिम कुंजी एक मान लापता था। यदि हमने बाद में एक अतिरिक्त कुंजी / मान जोड़ा है:
a4_plus = a4.dup # just to have a new-but-related variable name
a4_plus.push(['lychee', 4])
# => [["apple", 1],
# ["banana", 2],
# [["orange", "seedless"], 3], # multi-value key
# ["durian"], # missing value
# ["lychee", 4]] # new well-formed item
a6_plus = a4_plus.flatten(1)
# => ["apple", 1, "banana", 2, ["orange", "seedless"], 3, "durian", "lychee", 4]
a7_plus = a6_plus.each_slice(2).to_a
# => [["apple", 1],
# ["banana", 2],
# [["orange", "seedless"], 3], # so far so good
# ["durian", "lychee"], # oops! key became value!
# [4]] # and we still have a key without a value
a4_plus == a7_plus # => false, unlike a4 == a7
और इससे मिलने वाले दो हैश महत्वपूर्ण तरीकों से अलग हैं:
ap Hash[a4_plus] # prints:
{
"apple" => 1,
"banana" => 2,
[ "orange", "seedless" ] => 3,
"durian" => nil, # correct
"lychee" => 4 # correct
}
ap Hash[a7_plus] # prints:
{
"apple" => 1,
"banana" => 2,
[ "orange", "seedless" ] => 3,
"durian" => "lychee", # incorrect
4 => nil # incorrect
}
(नोट: मैं उपयोग कर रहा हूँ awesome_print
's ap
। बस यह आसान यहाँ संरचना दिखाने के लिए बनाने के लिए, वहाँ इस के लिए कोई वैचारिक आवश्यकता है)
तो each_slice
असंतुलित फ्लैट इनपुट का समाधान केवल तभी काम करता है जब असंतुलित बिट बहुत अंत में हो।
[key, value]
जोड़े के रूप में इनपुट सेट करें (बाहरी सरणी में प्रत्येक आइटम के लिए एक उप-सरणी)।#to_h
या Hash::[]
दोनों कार्य नहीं करेगा।Hash::[]
splat ( *
) के साथ संयुक्त करने में असमर्थ हैं , तो लंबे समय तक इनपुट संतुलित रहेंगे ।value
आइटम केवल एक है जिसकी कमी है है।साइड-नोट: मैं इस उत्तर को पोस्ट कर रहा हूं क्योंकि मुझे लगता है कि इसमें जोड़े जाने के लिए मूल्य है - कुछ मौजूदा उत्तरों में गलत जानकारी है, और कोई भी (जो मैंने पढ़ा है) ने एक उत्तर के रूप में पूरा किया, जैसा कि मैं यहां करने का प्रयास कर रहा हूं। मुझे आशा है कि यह मददगार है। मैं फिर भी उन लोगों को धन्यवाद देता हूं जो मेरे सामने आए, जिनमें से कई ने इस उत्तर के कुछ हिस्सों के लिए प्रेरणा प्रदान की।
उत्तर पर लागू होता है लेकिन अनाम सरणियों और एनोटेटिंग का उपयोग करते हुए:
Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
उस जवाब को अलग लेते हुए, अंदर से शुरू करते हुए:
"a,b,c,d"
वास्तव में एक स्ट्रिंग है।split
अल्पविराम में एक सरणी में।zip
निम्नलिखित सरणी के साथ मिलकर।[1,2,3,4]
एक वास्तविक सरणी है।मध्यवर्ती परिणाम है:
[[a,1],[b,2],[c,3],[d,4]]
चपटे तो उसे बदल देती है:
["a",1,"b",2,"c",3,"d",4]
और फिर:
*["a",1,"b",2,"c",3,"d",4]
में है कि नियंत्रित करता है
"a",1,"b",2,"c",3,"d",4
जो हम Hash[]
विधि के तर्क के रूप में उपयोग कर सकते हैं :
Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
कौन सी पैदावार:
{"a"=>1, "b"=>2, "c"=>3, "d"=>4}
*
) और समतल: Hash[("a,b,c,d".split(',').zip([1,2,3,4]))]
=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
। मैंने जो जवाब दिया उसमें और अधिक विस्तार।
यदि आपके पास ऐसा है जो इस तरह दिखता है -
data = [["foo",1,2,3,4],["bar",1,2],["foobar",1,"*",3,5,:foo]]
और आप चाहते हैं कि प्रत्येक सरणी के पहले तत्व हैश के लिए कुंजियाँ बनें और बाकी तत्व मान सरणियाँ बनें, तो आप कुछ इस तरह कर सकते हैं -
data_hash = Hash[data.map { |key| [key.shift, key] }]
#=>{"foo"=>[1, 2, 3, 4], "bar"=>[1, 2], "foobar"=>[1, "*", 3, 5, :foo]}
यकीन नहीं है कि यह सबसे अच्छा तरीका है, लेकिन यह काम करता है:
a = ["apple", 1, "banana", 2]
m1 = {}
for x in (a.length / 2).times
m1[a[x*2]] = a[x*2 + 1]
end
b = [["apple", 1], ["banana", 2]]
m2 = {}
for x,y in b
m2[x] = y
end
यदि संख्यात्मक मान seq अनुक्रमित हैं, तो हमारे पास सरल तरीके हो सकते हैं ... यहां मेरा कोड सबमिशन है, माई रूबी थोड़ा सा जंग है
input = ["cat", 1, "dog", 2, "wombat", 3]
hash = Hash.new
input.each_with_index {|item, index|
if (index%2 == 0) hash[item] = input[index+1]
}
hash #=> {"cat"=>1, "wombat"=>3, "dog"=>2}