[英]Ruby: How can I convert this array into this hash?
我有一个数组数组。 数组中的每个项目都包含三个字符串:一个腿数,一个动物和一个声音。
a = [ ['4', 'dog', 'woof'] , ['4', 'cow', 'moo'], ['2', 'human', 'yo'] , ['2', 'yeti', 'wrarghh'] ]
我想把数组变成这个哈希:
{
'2' => [ { 'human' => 'yo' }, { 'yeti' => 'wrarghh'} ],
'4' => [ { 'dog' => 'woof' }, { 'cow' => 'moo'} ]
}
我以为减少将是必经之路,但我运气不佳。 我当前的刺刺看起来像:
a.reduce({}) do |acc, item|
acc[item.first] = [] unless acc.key? item.first
acc[item.first] << { item[1] => item[2] }
end
但它得到一个错误:
NoMethodError: undefined method `key?' for [{"dog"=>"woof"}]:Array
实现此目标的最佳方法是什么?
a.each_with_object({}) { |(kout, kin, val), h| (h[kout] ||= []) << { kin => val } }
#=> {"4"=>[{"dog"=>"woof"}, {"cow"=>"moo"}], "2"=>[{"man"=>"yo"}, {"yeti"=>"wrarghh"}]}
我们有
enum = a.each_with_object({})
#=> #<Enumerator: [["4", "dog", "woof"], ["4", "cow", "moo"], ["2", "man", "yo"],
# ["2", "yeti", "wrarghh"]]:each_with_object({})>
第一个值由该枚举器生成并传递到块,并且为块变量分配了值:
(kout, kin, val), h = enum.next
#=> [["4", "dog", "woof"], {}]
分解如下。
kout
#=> "4"
kin
#=> "dog"
val
#=> "woof"
h #=> {}
因此,块计算为
(h[kout] ||= []) << { kin => val }
#=> (h[kout] = h[kout] || []) << { "dog" => "wolf" }
#=> (h["4"] = h["4"] || []) << { "dog" => "wolf" }
#=> (h["4"] = nil ||= []) << { "dog" => "wolf" }
#=> (h["4"] = []) << { "dog" => "wolf" }
#=> [] << { "dog" => "wolf" }
#=> [{ "dog" => "wolf" }]
h["4"] || [] #=> []
h["4"] || [] #=> []
因为h
没有键"4"
,因此h["4"] #=> nil
。
enum
的下一个值传递到该块,并重复计算。
(kout, kin, val), h = enum.next
#=> [["4", "cow", "moo"], {"4"=>[{"dog"=>"woof"}]}]
kout
#=> "4"
kin
#=> "cow"
val
#=> "moo"
h #=> {"4"=>[{"dog"=>"woof"}]}
(h[kout] ||= []) << { kin => val }
#=> (h[kout] = h[kout] || []) << { "cow" => "moo" }
#=> (h["4"] = h["4"] || []) << { "cow" => "moo" }
#=> (h["4"] = [{"dog"=>"woof"}] ||= []) << { "cow" => "moo" }
#=> (h["4"] = [{"dog"=>"woof"}]) << { "cow" => "moo" }
#=> [{"dog"=>"woof"}] << { "cow" => "moo" }
#=> [{ "dog" => "wolf" }, { "cow" => "moo" }]
这次h["4"] || [] #=> [{ "dog" => "wolf" }]
h["4"] || [] #=> [{ "dog" => "wolf" }]
因为h
现在具有带有真实值的键"4"
( [{ "dog" => "wolf" }]
)。
其余计算类似。
您可以使用,但是,对于reduce
,该块的返回值(即最后一行)成为acc
的下一个值(在这种情况下) acc
,因此您需要更改的是:
a.reduce({}) do |acc, item|
acc[item.first] = [] unless acc.key? item.first
acc[item.first] << { item[1] => item[2] }
acc # just add this line
end
由于Array#<<
的返回值是数组本身,因此第二次迭代将acc
作为第一个元素的数组。 当然,有很多方法可以做到这一点,有些方法可以说是更清洁的方法,但是当发现某些我认为不可行的方法时,知道发生了什么错误是很有用的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.