2016-04-09 24 views
1

Toplam dizileri, konturları ve turları aşağıdaki diziden nasıl döndürebilirim?Yuvalanmış hash değerinden Ruby toplamı

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

Aşağıdakileri yaparak vuruşları bulabilirim, ancak bunu yapmanın en iyi yolu olmadığını biliyorum.

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

Yukarıdaki dizi verilen vuruşların toplamını nasıl iade edebilirim?

+0

nesnenin verilmezse 'players', daha iyi olabilir bunu bir karma olarak temsil etmek için: '{" Angel Cabrera "=> {" skoru "=> 2," vuruş "=> 146," mermi "=> 3}, ...}'. 'Nil' değerini içeren 'oyuncuların' öğeleriyle ne yapmak istediğinizi açıklamalısınız.Onların atlanacağını farz ettim, ama başlangıçta, 'nil' kelimesini fark etmedim, bu da benim kodumda bir hatayla sonuçlandı. –

cevap

1

Bunu yapmanın üç yolu vardır. (Burada

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} 

adımları birleştirilen iki karma mevcut anahtarların değerlerini belirlemek için bir bloğu kullanıldığı Hash#update hazırlayınız aka merge!), her iki karmada bulunan anahtarların değerlerini belirlemek için { |_,o,v| o+v } satırını kullanır. İlk blok değişkeni (kullanılmayan ve bu nedenle _ yerel değişkeni ile temsil edilebilir) anahtardır, ikincisi (o, "eski" için) anahtarın değeri h ve üçüncü (n, "new"), anahtarın g'daki değeridir.

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 değişken blok ile temsil edilen sıfır varsayılan değer boş bir karma oluşturan bir sayma HASH kullanın. Bu demektir ki, h karması k anahtarına sahip değilse, h[k] varsayılan değeri döndürür (ancak karmayı değiştirmez).

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

h ise sağ tarafında bir kilit k, h[k] nedenle 0 ile değiştirilir yok: için h[k] += g[k] yukarıda genişler.

Sum değerleri ve Yakut v1.9 + kullanıyor ve anahtarlar her karma aynı sırada olmasını garanti o zaman bir karma

dönüştürmek, bu yapılabilir bir üçüncü yol gibidir aşağıdaki gibidir: (yukarıdaki b başlayarak)

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

adımlar şunlardır:

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

kullanın bu kodu: Burada

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

puts @total