数组到哈希:单词计数

时间:2012-02-28 11:14:04

标签: ruby

我有一些单词,我想得到一个哈希,其中键是单词,值是字数。

有没有比我更好的方式:

result = Hash.new(0)
words.each { |word| result[word] += 1 }
return result

5 个答案:

答案 0 :(得分:57)

您使用的命令式方法可能是Ruby中最快的实现方式。通过一些重构,你可以写一个单行:

wf = Hash.new(0).tap { |h| words.each { |word| h[word] += 1 } }

使用Enumerable#each_with_object的另一种必要方法:

wf = words.each_with_object(Hash.new(0)) { |word, acc| acc[word] += 1 }

使用现有抽象的功能/不可变方法:

wf = words.group_by(&:itself).map { |w, ws| [w, ws.length] }.to_h

请注意,这仍然是 O(n),但它会遍历集合三次,并在此过程中创建两个中间对象。

最后:频率计数器/直方图是一些常见的抽象,你会在像Facets这样的库中找到它:Enumerable#frequency

require 'facets'
wf = words.frequency

答案 1 :(得分:7)

使用inject

str = 'I have array of words and I want to get a hash, where keys are words'
result = str.split.inject(Hash.new(0)) { |h,v| h[v] += 1; h }

=> {"I"=>2, "have"=>1, "array"=>1, "of"=>1, "words"=>2, "and"=>1, "want"=>1, "to"=>1, "get"=>1, "a"=>1, "hash,"=>1, "where"=>1, "keys"=>1, "are"=>1}

我不知道效率。

答案 2 :(得分:2)

irb(main):001:0> %w(foo bar foo bar).each_with_object(Hash.new(0)) { |w, m| m[w] += 1 }
=> {"foo"=>2, "bar"=>2}

as @mfilej说

答案 3 :(得分:0)

发布了相关问题,但也发布在此处以提高知名度:

Ruby 2.7及更高版本将具有Enumerable#tally方法来解决此问题。

从后备箱documentation

  

统计集合。返回一个哈希值,其中键是元素,值是集合中与键相对应的元素数。

["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}

答案 4 :(得分:0)

这个很优雅:

  words.group_by(&:itself).transform_values(&:count)