У меня есть массив слов, и я хочу получить хеш, где ключи - слова и значения - количество слов.
Есть ли еще более красивый способ, чем мой:
result = Hash.new(0)
words.each { |word| result[word] += 1 }
return result
У меня есть массив слов, и я хочу получить хеш, где ключи - слова и значения - количество слов.
Есть ли еще более красивый способ, чем мой:
result = Hash.new(0)
words.each { |word| result[word] += 1 }
return result
Используемый вами императивный подход, вероятно, является самой быстрой реализацией в 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 #quency.
require 'facets'
wf = words.frequency
С 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}
Я не знаю об эффективности.
irb(main):001:0> %w(foo bar foo bar).each_with_object(Hash.new(0)) { |w, m| m[w] += 1 }
=> {"foo"=>2, "bar"=>2}
как @mfilej сказал
Я сделал что-то похожее на вышеупомянутые ответы, но немного отличался. Надеюсь, это может помочь кому-то.
arr = ['a','b','a']
hash = {}
arr.uniq.each do |e|
hash[e] = arr.count(e)
end
puts hash
Размещено по смежному вопросу, но также для наглядности:
В Ruby 2.7 и далее будет использоваться метод Enumerable#tally
, который решит эту проблему.
Из багажной документации:
Подсчитывает коллекцию. Возвращает хеш, где ключи - это элементы, а значения - номера элементов в коллекции, которые соответствуют ключу.
["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}