[英]Ruby sum from nested hash
How can I return the total scores, strokes and rounds from the following array? 如何从以下数组中返回总分,笔划和回合?
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}}]
I can get the strokes by doing the following but I know that isn't the best way to do it. 我可以通过执行以下操作来中风,但是我知道这不是最好的方法。
players.each do |x|
x.values()[0]["strokes"]
end
How can I return the sum of the strokes given the array above? 给定上面的数组,如何返回笔画的总和?
Use this code: 使用此代码:
@total= 0
players.each do |x|
a= x.values[0]
if a.class == Hash
@total += a["strokes"]
end
end
puts @total
Here are three ways of doing that. 这是三种方法。
Use the form of Hash#update that employs a block to determine the values of keys that are present in both hashes being merged 使用采用块的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}
The steps: 步骤:
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}
Here, Hash#update
(aka merge!
) uses the block { |_,o,v| o+v }
在这里,
Hash#update
(又名merge!
)使用块{ |_,o,v| o+v }
{ |_,o,v| o+v }
) to determine the values of keys that are present in both hashes. { |_,o,v| o+v }
)来确定两个哈希中都存在的键的值。 The first block variable (which is not used, and therefore can be represented by the local variable _
) is the key, the second ( o
, for "old") is the value of the key in h
and the third ( n
, for "new") is the value of the key in g
. 第一个块变量(未使用,因此可以用局部变量
_
)是键,第二个( o
,表示“ old”)是键在h
的值,第三个( n
,表示“ new”)是g
键的值。
Use a counting hash 使用计数哈希
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)
creates an empty hash with a default value of zero, represented by the block variable g
. Hash.new(0)
创建一个默认值为零的空哈希,由块变量g
。 This means that if a hash h
does not have a key k
, h[k]
returns the default value (but does not alter the hash). 这意味着,如果哈希
h
没有键k
,则h[k]
返回默认值(但不会更改哈希)。 h[k] += g[k]
above expands to: h[k] += g[k]
扩展为:
h[k] = h[k] + g[k]
If h
does not have a key k
, h[k]
on the right side is therefore replaced by 0
. 如果
h
没有密钥k
,那么右侧的h[k]
因此被0
代替。
Sum values and then convert to a hash 对值求和,然后转换为哈希
If you are using Ruby v1.9+ and the keys are guaranteed to have the same order in each hash, a third way it could be done is as follows: 如果您使用的是Ruby v1.9 +,并且确保每个哈希中的键具有相同的顺序,则可以采用的第三种方法如下:
["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}
The steps (starting from b
above) are: 步骤(从上面的
b
开始)是:
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}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.