web-dev-qa-db-ja.com

Rubyハッシュの配列。group_byと1行で変更

私はハッシュの配列を持っています、のようなもの

[ {: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のためであるため、これを1行で行う必要があります。

17
jtomasrl
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"]}
18
sawa

初期配列に対する1回の反復で:

arry.inject(Hash.new([])) { |h, a| h[a[:type]] += [a[:name]]; h }
16
Nikita Chernov
array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}
2
spas

私は以下のようにします:

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"]}
2
Arup Rakshit

ActiveSuportの Hash#transform_values

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

@ 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]を受け取り、[group_key, new_array](外側のArray)のblockを返します。
  3. そして最後に、to_hArray of ArraysをHashに変換します(この[[gk1,arr1],[gk2,arr2]...]をこの{ gk1 => arr1, gk2 => arr2, ...}に変換します)

上記のステップ(2)で説明されていない1つの欠落したステップがあります。 new_arrayv.map {|h| h[at]}によって作成され、atの各元のHashh)要素の値arrayをキャストします(したがって、Array of HashesからArrayの要素に移動します)。

他の人が例を理解するのに役立つことを願っています。

0
rellampec