রুবিতে, নিম্নলিখিত ফর্মগুলির মধ্যে একটি অ্যারে দেওয়া হয়েছে ...
[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
কনস্ট্রাক্টর সমান দৈর্ঘ্যের একটি অ্যারের আশা করছিল (উদাঃ ['কে 1', 'ভি 1,' কে 2 ',' ভি 2 '])। সবচেয়ে খারাপটি হ'ল একটি আলাদা অ্যারে যা একটি দৈর্ঘ্যের সমতল হয়ে যায় কেবল চুপচাপ আমাদেরকে ভুল মান সহ একটি হ্যাশ দেয়।
আপনি যদি অ্যারে কী বা মানগুলি ব্যবহার করতে চান তবে আপনি মানচিত্রটি ব্যবহার করতে পারেন :
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
রুবি ২.১.০ এ একটি ব্লক ছাড়াই চালু হয়েছিল।
রুবি ২.১ এর আগে, কেউ কম স্পষ্টত ব্যবহার করতে পারে 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]}
কীভাবে চাই ?
হালনাগাদ
রুবি ২.১.০ আজ প্রকাশিত হয়েছে । আর আমি দিয়ে আসে Array#to_h
( রিলিজ নোট এবং রুবি-ডক ), যা একটি রূপান্তর ইস্যু solves Array
একটি থেকেHash
।
রুবি ডক্স উদাহরণ:
[[:foo, :bar], [1, 2]].to_h # => {:foo => :bar, 1 => 2}
সম্পাদনা: আমি লেখার সময় পোস্ট করা প্রতিক্রিয়া দেখেছি, হ্যাশ [এফ্ল্যাটেন] যাবার উপায় মনে হচ্ছে। আমি যখন প্রতিক্রিয়ার মধ্য দিয়ে ভাবছিলাম তখন অবশ্যই ডকুমেন্টেশনে সেই বিটটি মিস করেছি। ভেবেছি যে সমাধানগুলি আমি লিখেছি প্রয়োজনে বিকল্প হিসাবে ব্যবহার করা যেতে পারে।
দ্বিতীয় ফর্মটি সহজ:
a = [[:apple, 1], [:banana, 2]]
h = a.inject({}) { |r, i| r[i.first] = i.last; r }
a = অ্যারে, এইচ = হ্যাশ, আর = রিটার্ন-ভ্যালু হ্যাশ (যেটিতে আমরা জমা করি), i = অ্যারেতে আইটেম
আমি প্রথম ফর্মটি করার কথা ভাবতে পারি এমন নেয়েটিস্ট উপায়টি হ'ল:
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
আপনি সহজেই 2D অ্যারে ব্যবহার করে হ্যাশে রূপান্তর করতে পারেন:
1.9.3p362 :005 > a= [[1,2],[3,4]]
=> [[1, 2], [3, 4]]
1.9.3p362 :006 > h = Hash[a]
=> {1=>2, 3=>4}
এই উত্তরটি অন্যান্য উত্তর থেকে প্রাপ্ত তথ্যের একটি বিস্তৃত মোড়ক হওয়ার আশাবাদী।
খুব সংক্ষিপ্ত সংস্করণ, প্রশ্ন এবং আরও কয়েকটি অতিরিক্ত থেকে প্রাপ্ত ডেটা দেওয়া:
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
এটি ভেরিয়েবলগুলি উপস্থাপন করতে চেয়েছিল others অন্যরা যেমন করেছে, আমি এখান থেকে স্ট্রিং ব্যবহার করব যাতে ইনপুট এবং ফলাফলগুলি মেলে)
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
(যা রুবি ২.১.০ এ দেখানো হয়েছে, এবং পূর্ববর্তী সংস্করণগুলিতে ব্যাকপোর্ট করা যেতে পারে )। প্রাথমিকভাবে-ফ্ল্যাট অ্যারের জন্য, এটি কাজ করে না:
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::[]
এখনও কাজ করে, কেবল মান nil
হিসাবে সেট করে durian
(এবং এ 4 এ অন্য কোনও অ্যারে উপাদান যা কেবলমাত্র 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
'রap
। শুধু এটা সহজ এখানে কাঠামো দেখানোর জন্য করতে, সেখানে এই জন্য কোন ধারণাগত প্রয়োজন থাকবে)
সুতরাং each_slice
ভারসাম্যহীন ফ্ল্যাট ইনপুটটির সমাধান কেবল তখনই কাজ করে যদি ভারসাম্যহীন বিট খুব শেষে থাকে।
[key, value]
জোড়া হিসাবে এই জিনিসগুলিতে ইনপুট সেট আপ করুন (বাইরের অ্যারেতে প্রতিটি আইটেমের জন্য একটি উপ-অ্যারে)।#to_h
বা Hash::[]
উভয়ই কাজ করবে।Hash::[]
তবে স্প্ল্যাটের সাথে মিলিত ( *
) কাজ করবে, যতক্ষণ ইনপুটগুলি ভারসাম্যযুক্ত ।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
যদি সংখ্যার মানগুলি সেক ইনডেক্স হয় তবে আমাদের আরও সহজ উপায় থাকতে পারে ... এখানে আমার কোড জমা দেওয়া হচ্ছে, আমার রুবি কিছুটা মরিচা
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}