计算元素在Ruby

时间:2016-05-25 15:28:52

标签: arrays ruby hashmap enumerable

这是将要处理的数组:

[{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]

我希望结果如下:

[{:name => "blake", :count => 2}, {:name => "ashley", :count => 1}]

我创建了一个名为" count"的新哈希然后我使用.each遍历数组,然后count[:count] += 1,但它没有给我我正在寻找的东西。

3 个答案:

答案 0 :(得分:7)

可以使用内置库调用来完成:

a = [{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]
a.group_by(&:itself)                   # group all of the identical elements together
 .map{|k, v| k.merge(count: v.length)} # add the "count" element to the hash

说明

.group_by(&:itself)将获取所有相同的组件,并将它们放在同一密钥下的哈希值中:

>> h = a.group_by(&:itself)
=> {
     {:name=>"blake"}  => [{:name=>"blake"}, {:name=>"blake"}],
     {:name=>"ashley"} => [{:name=>"ashley"}]
    }

注意哈希中的第一个条目如何具有两个相同元素的数组,第二个条目具有一个元素的数组。要创建那些计数,我们可以在哈希值的数组上使用.length方法:

>> k, v = h.first
>> v
=> [{:name=>"blake"}, {:name=>"blake"}]

>> v.length
=> 2

然后我们可以使用.map将该代码应用于散列中的每个元素:

>> h.map{|k, v| [k, v.length]}.to_h
=> {
     {:name=>"blake"}=>2,
     {:name=>"ashley"}=>1
   }

最后,.merge将采用两个哈希并将它们组合成一个哈希:

>> {:name=>"blake"}.merge({:count => 1})
=> {:name=>"blake", :count=>1}

答案 1 :(得分:1)

以下是 Ruby 2.7.0 引入的新Enumerable#tally

h = [{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]

h.tally.map {|k, v| k.merge({count: v}) }
#=> [{:name=>"blake", :count=>2}, {:name=>"ashley", :count=>1}]

答案 2 :(得分:0)

这有三种主要方法。

使用Enumerable#group_by

这就是@ user12341234在他或她的回答中所做的。

使用计数哈希

如果您的数组是arr

arr.each_with_object(Hash.new(0)) { |g,h| h[g[:name]] += 1 }.
    map { |name, count| { :name=>name, :count=>count } }
  #=> [{:name=>"blake", :count=>2}, {:name=>"ashley", :count=>1}]

有关详细信息,请参阅Hash::new

使用Hash#update(aka merge!)的形式使用块来确定合并的两个哈希中存在的键的值。

arr.each_with_object({}) { |g,h| h.update(g[:name]=>1) { |_,o,n| o+n } }.
    map { |name, count| { :name=>name, :count=>count } }
  #=> [{:name=>"blake", :count=>2}, {:name=>"ashley", :count=>1}]

有关详细信息,请参阅文档Hash#update

请注意,#2和#3的最后一行是相同的。

我不能说其中一种方法比其他方法更好。