我有一个多维数组,例如:
array = [["stop", "halt"],["stop", "red"],["go", "green"],["go","fast"],["caution","yellow"]]
我想把它变成这样的哈希:
hash = {"stop" => ["halt","red"], "go" => ["green","fast"], "caution" => "yellow"}
但是,当我在array.to_h时,这些值会相互覆盖并得到:
hash = {"stop" => "red", "go" => "fast", "caution" => "yellow"}
如何获得所需的数组?
答案 0 :(得分:2)
这是一种方式。它使用Enumerable#each_with_object和Hash#update(又名merge!
)的形式,它使用一个块来确定合并的两个哈希中存在的键的值。
array << ["stop", "or I'll fire!"]
array.each_with_object({}) { |(f,l),h|
h.update(f=>l) { |_,ov,nv| ov.is_a?(Array) ? ov << nv : [ov, nv] } }
#=> {"stop"=>["halt", "red", "or I'll fire!"],
# "go"=>["green", "fast"],
# "caution"=>"yellow"}
如果您希望返回的哈希值中的所有值都是数组(即"caution"=>["yellow"]
),则代码会被简化,这通常对后续计算更方便:
array.each_with_object({}) { |(f,l),h| h.update(f=>[l]) {|_,ov,nv| ov+nv }}
#=> {"stop"=>["halt", "red", "or I'll fire!"],
# "go"=>["green", "fast"],
# "caution"=>["yellow"]}
答案 1 :(得分:1)
一种方法:
array.inject({}) {|r, (k, v)| r[k] &&= [*r[k], v]; r[k] ||= v; r }
但这很混乱。写出来,看起来像这样:
def to_hash_with_duplicates(arr)
{}.tap do |r|
arr.each do |k, v|
r[k] &&= [*r[k], v] # key already present, turn into array and add value
r[k] ||= v # key not present, simply store value
end
end
end
编辑:再考虑一下,@cary-swoveland
使用块更新解决方案会更好,因为它可以正确处理nil
和false
值。