如何从数组的哈希中提取信息

时间:2017-07-21 01:36:55

标签: ruby-on-rails arrays ruby hash

我试图得到一个新的数组哈希值,它会列出每个:在数组(e)的哈希值中只提供一次的名称,该值应该是总得分,它应该是相同的得分总和:数组中的名称(e)。

e = [
{:name => "Oyster", :score => 1000},
{:name => "Tiger", :score => 2000},
{:name => "Frog", :score => 2300},
{:name => "Frog", :score => 1220},
{:name => "Tiger", :score => 200},
{:name => "Frog", :score => 1000},
{:name => "Oyster", :score => 2000},
{:name => "Frog", :score => 300},
{:name => "Monkey", :score => 500},
{:name => "Oyster", :score => 3300}
]

我搜索了谷歌的“哈希数组红宝石”和红宝石的文档,但还没有得到任何非常有用的信息。

我尝试通过执行以下操作来解决此问题:

f = e.map{|t|t[:name]}.uniq
n = Hash[f.map{|v|[v,0]}]
result = n.map{|key, value|e.map{|t| if key == t[:name]; n[key] += t[:score].to_i end}}

但结果是

[[1000, nil, nil, nil, nil, nil, 3000, nil, nil, 6300], [nil, 2000, nil, nil, 2200, nil, nil, nil, nil, nil], [nil, nil, 2300, 3520, nil, 4520, nil, 4820, nil, nil], [nil, nil, nil, nil, nil, nil, nil, nil, 500, nil]]

它与我的期望完全不同。 如果我们想要达到非常整洁的结果,我们应该做些什么。

4 个答案:

答案 0 :(得分:0)

您可以使用group_by按照:name对哈希值进行分组,然后使用:score:reducemerge值进行求和,如下所示:

e.group_by { |h| h[:name] }.map do |_, v| 
  v.reduce do |acc, h| 
    acc.merge(h) { |k, ov, nv| k == :name ? ov : ov + nv }
  end
end

#=> [{:name=>"Oyster", :score=>6300}, {:name=>"Tiger", :score=>2200}, {:name=>"Frog", :score=>4820}, {:name=>"Monkey", :score=>500}]

说明:

  • group_by { |h| h[:name] }按名称对所有哈希值进行分组,产生如下内容:

    {
      "Oyster"=>[
        {:name=>"Oyster", :score=>1000},
        {:name=>"Oyster", :score=>2000},
        {:name=>"Oyster", :score=>3300}
      ],
      "Tiger"=>[...]
    }
    
  • .map迭代生成的哈希,忽略分组键(_变量)并仅使用值(v变量,其中包含分组哈希数组)到将每个哈希的得分相加(见下一步)。

  • reduce通过将数组中的所有哈希值合并在一起来对score的值进行求和(acc累积的值/哈希值h 1}}是迭代的当前值/哈希)。请注意,merge与块一起使用,而不是替换重复键的值(如没有块的merge),它将使用块中的代码替换其值: / p>

    • k是要合并的哈希的当前密钥。
    • ov是给定密钥的旧值(即acc哈希的值)。
    • nv是给定密钥的新值(即h哈希的值)。

因此,在通过name对哈希进行分组之后,它会迭代每组哈希值并将它们合并为一个哈希值,首先评估当前密钥是否为:name,如果是,则保留旧密码值(例如"Oyster"),否则(例如:score)它会将旧值与新值相加,并将score的值替换为该结果,累积每次迭代的值。

答案 1 :(得分:0)

我知道这篇文章已经有了一个接受的答案,但是如果你不希望结果是一个哈希数组,只想得到给定名称的给定分数,你可以:

e.inject({}) do |totals, current| 
  totals[current[:name]] = (totals[current[:name]] || 0) + current[:score] 
  totals
end

#=> {"Oyster"=>6300, "Tiger"=>2200, "Frog"=>4820, "Monkey"=>500}

答案 2 :(得分:0)

试试这个:

new_array = []
e.each{|h| new_array << { h[:name] => h[:score]} }
new_array.inject{|name, score| name.merge( score ){|k, old_v, new_v| old_v + new_v}}


#=> {"Oyster"=>6300, "Tiger"=>2200, "Frog"=>4820, "Monkey"=>500}

答案 3 :(得分:0)

您可以构建使用Hash::new创建的哈希值,默认值为零(有时称为计算哈希值),然后将哈希值转换为哈希值数组。有关详细信息,请参阅文档。

#calendar li:hover  > .date {
  text-decoration: underline;
}