我有这个数组数组:
[[F1,State1,Blah1],[F2,State1,Blah2],[F1,State2,Blah3]]
什么是一种巧妙的红宝石方式将上述内容转换为:
{State1=>[F1,F2],State2=>[F1]}
答案 0 :(得分:4)
arr = [['F1','State1','Blah1'],['F2','State1','Blah2'],['F1','State2','Blah3']]
arr.group_by{|a| a[1]}.map {|k,v| [k, v.map(&:first)] }.to_h
# => {"State1"=>["F1", "F2"], "State2"=>["F1"]}
答案 1 :(得分:2)
inject
的一次性解决方案:
array.inject({}) { | a, (v, k, _) | a[k] ||= []; a.update(k => a[k] << v) }
或者说有点清洁:
array.inject(Hash.new { | h, k | h[k] = [] }) { | a, (v, k, _) | a.update(k => a[k] << v) }
这是写作的功能性方式:
result = {}
array.each do | v, k, _ |
result[k] = [] unless result.has_key? k
result[k] << v
end
如果遇到性能问题,应避免使用update
:
array.inject({}) { | a, (v, k, _) | a[k] ||= []; a[k] << v; a }
为了完整起见,还有each_with_object
在这里更合适:
array.each_with_object({}) { | (v, k, _), a | a[k] ||= []; a[k] << v }
答案 2 :(得分:1)
另一种方法是使用Hash#update(aka merge!
)的形式,它使用块来确定存在的键的值在两个哈希合并中:
arr = [['F1','State1','Blah1'],['F2','State1','Blah2'],['F1','State2','Blah3']]
arr.each_with_object({}) { |(v,k,_),h| h.update(k=>[v]) { |_,ov,nv| ov+nv } }
#=> { "State1"=>["F1","F2"],"State2"=>["F1"] }