Ruby数组哈希。 group_by并在一行中修改

时间:2013-09-20 15:48:35

标签: ruby-on-rails ruby hash enumerable

我有一系列哈希,比如

[ {: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"}] }

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

6 个答案:

答案 0 :(得分:16)

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

答案 1 :(得分:16)

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

arry.inject(Hash.new([])) { |h, a| h[a[:type]] += [a[:name]]; h }

答案 2 :(得分:2)

array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}

答案 3 :(得分: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"]}

答案 4 :(得分:1)

使用ActiveSuport&#39; Hash#transform_values

array.group_by{ |h| h[:type] }.transform_values{ |hs| hs.map{ |h| h[:name] } }
#=> {"Meat"=>["one", "two"], "Fruit"=>["four"]}

答案 5 :(得分: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]并返回Array(外部[group_key, new_array])中的block
  3. 最后to_hArray of Array转换为Hash(此[[gk1,arr1],[gk2,arr2]...]转换为{ gk1 => arr1, gk2 => arr2, ...}

有一个遗漏的步骤在上面的步骤(2)中没有解释。 new_arrayv.map {|h| h[at]}制作,该方法将at的每个原始Hashh)元素的值array转换为{从Array of Hash个元素移到Array个元素)。

希望可以帮助其他人理解示例。