Ruby on rails 基于嵌套散列的Ruby求和

Ruby on rails 基于嵌套散列的Ruby求和,ruby-on-rails,ruby,Ruby On Rails,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"=>

如何从以下数组中返回总分、笔划和回合数

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
如何返回给定上述数组的笔划总数?

使用以下代码:

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

puts @total
使用此代码:

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

puts @total

这里有三种方法

使用使用块的形式来确定合并的两个哈希中存在的键的值

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}
步骤如下:

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
(也称为
merge!
)使用块
{u124;,o,v | o+v}
)来确定两个哈希中存在的键的值。第一个块变量(未使用,因此可由局部变量
\uu
表示)是键,第二个(
o
,表示“旧”)是
h
中键的值,第三个(
n
,表示“新”)是
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]+=g[k]
以上扩展为:

h[k] = h[k] + g[k]
如果
h
没有键
k
,则右侧的
h[k]
将因此替换为
0

求和值,然后转换为哈希值

players.map { |g| g.first.last }.
        compact.
        each_with_object(Hash.new(0)) { |g,h| g.keys.each { |k| h[k] += g[k] } }
如果您使用的是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}
步骤(从上面的
b
开始)包括:


这里有三种方法

使用使用块的形式来确定合并的两个哈希中存在的键的值

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}
步骤如下:

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
(也称为
merge!
)使用块
{u124;,o,v | o+v}
)来确定两个哈希中存在的键的值。第一个块变量(未使用,因此可由局部变量
\uu
表示)是键,第二个(
o
,表示“旧”)是
h
中键的值,第三个(
n
,表示“新”)是
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]+=g[k]
以上扩展为:

h[k] = h[k] + g[k]
如果
h
没有键
k
,则右侧的
h[k]
将因此替换为
0

求和值,然后转换为哈希值

players.map { |g| g.first.last }.
        compact.
        each_with_object(Hash.new(0)) { |g,h| g.keys.each { |k| h[k] += g[k] } }
如果您使用的是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}
步骤(从上面的
b
开始)包括:


如果没有为您提供对象
玩家
,则最好将其表示为哈希:
{“Angel Cabrera”=>{“score”=>2,“strokes”=>146,“rounds”=>3},…}
。您应该解释如何处理包含
nil
值的
players
元素。我假设它们将被跳过,但最初没有注意到孤零零的
nil
,这导致了我的代码中的一个错误。如果没有给对象
players
,那么最好将其表示为散列:
{“Angel Cabrera”=>{“score”=>2,“strokes”=>146,“rounds”=>3},
。您应该解释如何处理包含
nil
值的
players
元素。我假设它们将被跳过,但最初没有注意到孤零零的
nil
,这导致了我的代码中的错误。谢谢,这个解释真的非常有用!谢谢,这个解释真的非常有用!