如何在Ruby中查找数组中唯一元素及其出现次数

43

我有一个包含若干元素的数组,如何获取每个元素在数组中出现的次数?

例如,已知以下数组:

a = ['cat', 'dog', 'fish', 'fish']

结果应该是:

a2 #=> {'cat' => 1, 'dog' => 1, 'fish' => 2}

我该怎么做?


可能是 如何在 Ruby 中将数字分组到不同的桶中 的重复问题。 - Andrew Grimm
12个回答

44

您可以使用Enumerable#group_by来实现此功能:

res = Hash[a.group_by {|x| x}.map {|k,v| [k,v.count]}]
#=> {"cat"=>1, "dog"=>1, "fish"=>2}

1
在我看来,子数组复制导致了过多的复杂性。 - Alex Fortuna
@dadooda,复杂性在于看待问题的角度。 - Cary Swoveland
1
请注意,自 Ruby 2.7 起,tally 方法正好可以做到这一点 https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-tally。因此,这不再是最佳答案。 - Andrew

27
a2 = a.reduce(Hash.new(0)) { |a, b| a[b] += 1; a }
#=> {"cat"=>1, "fish"=>2, "dog"=>1}

2
使用默认预设值的Hash.new(0)非常方便! - Alex Fortuna

15

Ruby 2.7新增了tally方法。

tally → a_hash

该方法可以对集合进行计数,即统计每个元素出现的次数。返回一个哈希表,其中集合中的元素作为键,相应的计数作为值。

['cat', 'dog', 'fish', 'fish'].tally  

=> {"cat"=>1, "dog"=>1, "fish"=>2}

10
a2 = {}
a.uniq.each{|e| a2[e]= a.count(e)}

1
“count”必须遍历整个数组。对于每个值都这样做相当低效。 - Stefan

8

在1.9.2中,你可以像这样做。从我的经验来看,相当多的人发现each_with_objectreduce/inject更易读(至少了解它的人):

a = ['cat','dog','fish','fish']
#=> ["cat", "dog", "fish", "fish"]

a2 = a.each_with_object(Hash.new(0)) { |animal, hash| hash[animal] += 1 }
#=> {"cat"=>1, "dog"=>1, "fish"=>2}

4
使用Arraycount方法获取计数。
a.count('cat')

4
如果他确实只需要在任何给定时间内计数一次,那么这将是一个不错的解决方案。然而,用这种方式处理大型列表是低效的。 - Mark Thomas

3
m = {}

a.each do |e|
  m[e] = 0 if m[e].nil?
  m[e] = m[e] + 1
end

puts m

3
a.inject({}){|h, e| h[e] = h[e].to_i+1; h }
#=> {"cat"=>1, "fish"=>2, "dog"=>1}

或n2解决方案
a.uniq.inject({}){|h, e| h[e] = a.count(e); h }
#=> {"cat"=>1, "fish"=>2, "dog"=>1}

3
a = ['cat','dog','fish','fish']
a2 = Hash[a.uniq.map {|i| [i, a.count(i)]}]

3
['cat','dog','fish','fish'].group_by(&:itself).transform_values(&:count)
=> {
     "cat" => 1,
     "dog" => 1,
    "fish" => 2
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接