组数组数组并在Ruby中选择一些列

时间:2015-02-19 10:22:24

标签: ruby

我有这个数组数组:

    [[F1,State1,Blah1],[F2,State1,Blah2],[F1,State2,Blah3]]

什么是一种巧妙的红宝石方式将上述内容转换为:

    {State1=>[F1,F2],State2=>[F1]}

3 个答案:

答案 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"] }