2016-04-09 9 views
1

次の配列から合計得点、ストローク、ラウンドを返すにはどうすればよいですか?ネストされたハッシュからのRuby合計

players = [{"Angel Cabrera"=>{"score"=>2, "strokes"=>146, "rounds"=>3}}, 
{"Jason Day"=>{"score"=>1, "strokes"=>145, "rounds"=>3}}, 
{"Bryson DeChambeau"=>{"score"=>0, "strokes"=>144, "rounds"=>3}}, 
{"Sergio Garcia"=>{"score"=>0, "strokes"=>144, "rounds"=>3}}, 
{"Ian Poulter"=>{"score"=>5, "strokes"=>162, "rounds"=>3}}, 
{"Vijay Singh"=>nil}, 
{"Jordan Spieth"=>{"score"=>-4, "strokes"=>140, "rounds"=>3}}] 

私は以下のことを行うことでストロークを得ることができますが、それを行う最良の方法ではないことは分かっています。

players.each do |x| 
    x.values()[0]["strokes"] 
    end 

上記の配列のストロークの合計を返すにはどうすればよいですか?

+0

あなたがオブジェクトを与えられていない場合は 'players'、それが良いかもしれません'{" Angel Cabrera "=> {"スコア "=> 2、"ストローク "=> 146、"ラウンド "=> 3}、...}' 'nil'の値を含む' players'要素で何をしたいのかを説明する必要があります。私はそれらをスキップすることを前提としていましたが、最初は孤独な 'nil'に気付かず、コードにバグがありました。 –

答えて

1

はそれを行うための3つの方法があります。

ここ
a = players.map { |g| g.first.last } 
    #=> [{"score"=> 2, "strokes"=>146, "rounds"=>3}, 
    # {"score"=> 1, "strokes"=>145, "rounds"=>3}, 
    # {"score"=> 0, "strokes"=>144, "rounds"=>3}, 
    # {"score"=> 0, "strokes"=>144, "rounds"=>3}, 
    # {"score"=> 5, "strokes"=>162, "rounds"=>3}, 
    # nil, 
    # {"score"=>-4, "strokes"=>140, "rounds"=>3}] 
b = a.compact 
    #=> [{"score"=> 2, "strokes"=>146, "rounds"=>3}, 
    # {"score"=> 1, "strokes"=>145, "rounds"=>3}, 
    # {"score"=> 0, "strokes"=>144, "rounds"=>3}, 
    # {"score"=> 0, "strokes"=>144, "rounds"=>3}, 
    # {"score"=> 5, "strokes"=>162, "rounds"=>3}, 
    # {"score"=>-4, "strokes"=>140, "rounds"=>3}] 
b.each_with_object({}) { |g,h| h.update(g) { |_,o,v| o+v } } 
    #=> {"score"=>4, "strokes"=>881, "rounds"=>18}  

Hash#update(:

はステップ

players.map { |g| g.first.last }. 
     compact. 
     each_with_object({}) { |g,h| h.update(g) { |_,o,v| o+v } } 
    #=> {"score"=>4, "strokes"=>881, "rounds"=>18} 

をマージされ、両方のハッシュに存在するキーの値を決定するためにブロックを使用Hash#updateの形式を使用します別名merge!)はブロック{ |_,o,v| o+v }を使用して)両方のハッシュに存在するキーの値を決定します。最初のブロック変数(使用されていないのでローカル変数_で表すことができます)はキーで、2番目の変数(o、 "古い"の場合)はhのキーの値で、3番目のブロック変数はn "new")は、gのキーの値です。

players.map { |g| g.first.last }. 
     compact. 
     each_with_object(Hash.new(0)) { |g,h| g.keys.each { |k| h[k] += g[k] } } 

Hash.new(0)ブロック変数gで表されるゼロのデフォルト値で空のハッシュを作成計数ハッシュを使用します。つまり、ハッシュhにキーkがない場合、h[k]はデフォルト値を返します(ただし、ハッシュは変更されません)。

h[k] = h[k] + g[k] 

hキーkを持っていない場合は、右側にh[k]は、したがって、0によって置き換えられます。上記のh[k] += g[k]はに展開されます。

合計値とあなたはRubyのV1.9 +を使用していて、キーが各ハッシュで同じ順序を持つことが保証されている場合は、ハッシュ

に変換し、それを行うことができる第三の方法は、通りです以下の:(上記bから開始)

["scores", "strokes", "rounds"].zip(
    players.map { |g| g.first.last }. 
      compact. 
      map(&:values). 
      transpose. 
      map { |arr| arr.reduce(:+) } 
).to_h 
    #=> {"scores"=>4, "strokes"=>881, "rounds"=>18} 

の手順は以下のとおりです。

c = b.map(&:values) 
    #=> [[ 2, 146, 3], 
    # [ 1, 145, 3], 
    # [ 0, 144, 3], 
    # [ 0, 144, 3], 
    # [ 5, 162, 3], 
    # [-4, 140, 3]] 
d = c.transpose 
    #=> [[ 2, 1, 0, 0, 5, -4], 
    # [146, 145, 144, 144, 162, 140], 
    # [ 3, 3, 3, 3, 3, 3]] 
totals = d.map { |arr| arr.reduce(:+) } 
    #=> [4, 881, 18] 
e = ["scores", "strokes", "rounds"].zip(totals) 
    #=> [["scores", 4], ["strokes", 881], ["rounds", 18]] 
e.to_h 
    #=> {"scores"=>4, "strokes"=>881, "rounds"=>18} 
2

は、このコードを使用します。ここでは

@total= 0 
players.each do |x| 
a= x.values[0] 
if a.class == Hash 
    @total += a["strokes"] 
end 
end 

puts @total 
関連する問題