Ruby: Как сгруппировать массив Ruby?
У меня есть массив Ruby
> list = Request.find_all_by_artist("Metallica").map(&:song)
=> ["Nothing else Matters", "Enter sandman", "Enter Sandman", "Master of Puppets", "Master of Puppets", "Master of Puppets"]
и мне нужен список с такими графами:
{"Nothing Else Matters" => 1,
"Enter Sandman" => 2,
"Master of Puppets" => 3}
В идеале я хочу, чтобы хэш дал мне счет и заметил, что у меня Enter Sandman
и Enter Sandman
, поэтому мне нужно, чтобы он не учитывал регистр. Я уверен, что смогу пройти через него, но есть ли более чистый способ?
Ответы
Ответ 1
list.group_by(&:capitalize).map {|k,v| [k, v.length]}
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]]
Группа создает хеш из версии capitalize
d имени альбома в массив, содержащий все строки в list
, которые соответствуют ему (например, "Enter sandman" => ["Enter Sandman", "Enter sandman"]
). map
затем заменяет каждый массив своей длиной, так что вы получаете, например. ["Enter sandman", 2]
для "Enter sandman"
.
Если вы хотите, чтобы результат был хэшем, вы можете вызвать to_h
в результате или обернуть вокруг него Hash[ ]
.
Ответ 2
list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}
Ответ 3
Другой вариант:
h = Hash.new {|hash, key| hash[key] = 0}
list.each {|song| h[song.downcase] += 1}
p h # => {"nothing else matters"=>1, "enter sandman"=>2, "master of puppets"=>3}
Как я уже сказал, вы можете предпочесть titlecase
Ответ 4
Группировка и сортировка набора данных неизвестного размера в Ruby должны быть последним средством. Это сложнейшая задача, оставленная БД. Обычно проблемы, подобные вашей, решаются с использованием комбинаций COUNT
, GROUP BY
, HAVING
и ORDER BY
. К счастью, рельсы предоставляют метод COUNT
для таких случаев использования.
song_counts= Request.count(
:select => "LOWER(song) AS song"
:group => :song, :order=> :song,
:conditions => {:artist => "Metallica"})
song_counts.each do |song, count|
p "#{song.titleize} : #{count}"
end