У меня есть массив слов, и я хочу получить хэш, где ключи - слова и значения - это количество слов.Array to Hash: count count
Есть ли более красивый способ, то мой:
result = Hash.new(0)
words.each { |word| result[word] += 1 }
return result
У меня есть массив слов, и я хочу получить хэш, где ключи - слова и значения - это количество слов.Array to Hash: count count
Есть ли более красивый способ, то мой:
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 { |w| w }.map { |w, ws| [w, ws.length] }.to_h
Обратите внимание, что это по-прежнему O (n) во времени, но три раза пересекает коллекцию и создает два промежуточных объекта на этом пути.
Итог: частота-счетчик/гистограмма - это общая абстракция, которую вы найдете в некоторых библиотеках, таких как Facets: Enumerable#frequency.
require 'facets'
wf = words.frequency
Может быть просто: 'str.split (" ") .reduce (Hash.new (0)) {| h, w | помещает h [w] + = 1; h} '? –
Некоторое испытание скорости соска, рубин 2.0.0p451 на macbook работает mavericks: Declarative: '100.times {words.inject (Hash.new 0) {| h, w | h [w] + = 1; h}} ': avg 1.17s. Imperative: '100.times {hist = Hash.new 0; words.each {| w | hist [w] + = 1}} ': avg 1.09s. 'words' был массивом из 10k случайных слов, генерация только одного массива заняла 0,2 с avg. то есть императив был примерно на 9% быстрее. –
Благодарим вас за последнюю заметку о Facets. Я уже несколько раз перепрограммировал это, и аспекты избавляют меня от необходимости повторного использования или запуска моей собственной стандартной библиотеки. Для других вы должны проверить Facets, это как расширение стандартной библиотеки Ruby. –
С 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
Это примерно в 10 раз медленнее, чем другие решения. – Sixty4Bit
Вы проводите курс Berkeley SaaS? – Gordon
Да, у меня есть решение, но вы ищете лучшие версии. – demas
если 'result [word]' не существует, он выдает исключение, потому что для 'n' нет' + '. –