2017-07-03 3 views
2

私はキーが国であり、値が日数であるハッシュの配列を持っています。ハッシュコレクション内のRuby集約選択値

私はハッシュを集計し、同じ国の値を合計したいと思います。 SO like this one

countries.inject{|new_h, old_h| new_h.merge(old_h) {|_, old_v, new_v| old_v + new_v}} 

[{"Country" => "Brazil", "Duration"=>1096/1 days}]は、私が試した他の質問{"Country"=>"BrazilBrazil", "Duration"=>1096/1 days}

を生成します:

配列は、これがcountries = [{"Country"=>"Brazil", "Duration"=>731/1 days}, {"Country"=>"Brazil", "Duration"=>365/1 days}]

私は、これはの行に何かを返したいが、のようになります。

特定のvalのみを選択的にマージする方法はありますかues?

答えて

2

次のようにあなたのコードを更新することがあります。

あなたは基本的に異なるマージポリシーを切り替えるための kキー用)引数を使用
countries.inject do |new_h, old_h| 
    new_h.merge(old_h) do |k, old_v, new_v| 
     if k=="Country" then old_v else old_v + new_v end 
    end 
end 
# => {"Country"=>"Brazil", "Duration"=>1096} 

を。

+0

伝説!ありがとう@metaphori – TheLegend

4

これはデフォルト値(ここでは0)で空のハッシュを作成し、作成しHash::newの形式を使用しています。そのようにハッシュhが作成された場合、h[k]は、ハッシュにキーがkでない場合、デフォルト値を返します。ハッシュは変更されません。

countries = [{"Country"=>"Brazil", "Duration"=>"731/1 days"}, 
      {"Country"=>"Argentina", "Duration"=>"123/1 days"}, 
      {"Country"=>"Brazil", "Duration"=>"240/1 days"}, 
      {"Country"=>"Argentina", "Duration"=>"260/1 days"}] 

countries.each_with_object(Hash.new(0)) {|g,h| h[g["Country"]] += g["Duration"].to_i }. 
    map { |k,v| { "Country"=>k, "Duration"=>"#{v}/1 days" } } 
    #=> [{"Country"=>"Brazil", "Duration"=>"971/1 days"}, 
    # {"Country"=>"Argentina", "Duration"=>"383/1 days"}] 

最初のハッシュがブロックに渡され、ブロック変数gに割り当てられます。

g = {"Country"=>"Brazil", "Duration"=>"731/1 days"} 

このとき、h #=> {}。私たちは、その後、

h[g["Country"]] += g["Duration"].to_i 
    #=> h["Brazil"] += "971/1 days".to_i 
    #=> h["Brazil"] = h["Brazil"] + 971 
    #=> h["Brazil"] = 0 + 971 # h["Brazil"] 

はなぜ"971/1 days".to_iリターン971の説明についてはString#to_iを参照してください計算します。 hは(まだ)キー"Brazil"を持っていないので、平等の権利の

h["Brazil"]0のデフォルト値を返します。右側のh["Brazil"]h.[]("Brazil")の構文砂糖であり、左側はh.[]=(h["Brazil"] + 97)の構文砂糖であることに注意してください。ハッシュに指定されたキーがない場合にデフォルト値を返すのはHash#[]です。残りの手順は同様です。

+0

'Hash.new(0)'は期間を秒に変換します。 'Hash.new(0.days)'を試してからマップブロックの中で 'Duration" => v' – TheLegend

+1

@ TheLegendを実行するとよいでしょう。私はRailsを知らないので、純粋なRubyソリューションを提供しました。 –

関連する問題