19

我有一个哈希数组,比如

[ {:type=>"Meat", :name=>"one"}, 
  {:type=>"Meat", :name=>"two"}, 
  {:type=>"Fruit", :name=>"four"} ]

我想把它转换成这个

{ "Meat" => ["one", "two"], "Fruit" => ["Four"]}

我试过group_by了,但后来我得到了这个

{ "Meat" => [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}],
  "Fruit" => [{:type=>"Fruit", :name=>"four"}] }

然后我不能修改它只留下名称而不是完整的哈希。我需要在一行中执行此操作,因为它适用grouped_options_for_select于 Rails 表单。

4

6 回答 6

22
array.group_by{|h| h[:type]}.each{|_, v| v.replace(v.map{|h| h[:name]})}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}

遵循 steenslag 的建议:

array.group_by{|h| h[:type]}.each{|_, v| v.map!{|h| h[:name]}}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}
于 2013-09-20T15:57:53.623 回答
16

在初始数组的单次迭代中:

arry.inject(Hash.new([])) { |h, a| h[a[:type]] += [a[:name]]; h }
于 2013-09-20T16:01:13.430 回答
3

使用 ActiveSuport 的Hash#transform_values

array.group_by{ |h| h[:type] }.transform_values{ |hs| hs.map{ |h| h[:name] } }
#=> {"Meat"=>["one", "two"], "Fruit"=>["four"]}
于 2016-10-27T21:04:56.473 回答
2
array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}
于 2013-09-20T16:00:18.523 回答
2

我会做如下:

hsh =[{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
p Hash[hsh.group_by{|h| h[:type] }.map{|k,v| [k,v.map{|h|h[:name]}]}]

# >> {"Meat"=>["one", "two"], "Fruit"=>["four"]}
于 2013-09-20T16:04:20.950 回答
0

@ArupRakshit answer,稍作修改(为了清楚起见,在最后一个示例中添加了该函数):

def group(list, by, at)
  list.group_by { |h| h[by] }.map { |k,v| [ k , v.map {|h| h[at]} ] }.to_h
end

sample =[
  {:type=>"Meat",  :name=>"one",  :size=>"big"   },
  {:type=>"Meat",  :name=>"two",  :size=>"small" },
  {:type=>"Fruit", :name=>"four", :size=>"small" }
]

group(sample, :type, :name) # => {"Meat"=>["one", "two"], "Fruit"=>["four"]}
group(sample, :size, :name) # => {"big"=>["one"], "small"=>["two", "four"]}

请注意,尽管问题中未提及,但您可能希望按原样保留原件sample。一些答案保留了这一点,而另一些则没有。

在分组 ( list.group_by {...}) 之后,进行转换的部分(不修改原始样本的值)是:

.map { |k,v| [ k , v.map {|h| h[at]} ] }.to_h

一些提示

  1. 迭代成对的Hash组(第一个map),其中
  2. 对于每次迭代,我们接收|group_key, array]并返回一个Arrayof [group_key, new_array](outer block),
  3. 最后to_hArray of Arrays 转换为Hash(this[[gk1,arr1],[gk2,arr2]...]转换为 this { gk1 => arr1, gk2 => arr2, ...})

上面的步骤(2)中没有说明一个缺失的步骤。new_arrayis made by v.map {|h| h[at]},它只是转换at每个原始Hash( h) 元素的值array(所以我们从Array of Hashes 移动到 an Arrayof 元素)。

希望能帮助其他人理解这个例子。

于 2018-08-10T08:16:23.300 回答