Ruby: Как сгруппировать массив Ruby? - PullRequest
45 голосов
/ 07 октября 2010

У меня есть массив 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, поэтому мне нужно, чтобы он был без учета регистра.Я почти уверен, что смогу пройти через это, но есть ли более чистый путь?

Ответы [ 5 ]

87 голосов
/ 07 октября 2010
list.group_by(&:capitalize).map {|k,v| [k, v.length]}
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]]

Группировка by создает хеш из capitalize d версии названия альбома в массив, содержащий все строки в list, которые ему соответствуют (например, "Enter sandman" => ["Enter Sandman", "Enter sandman"]).map затем заменяет каждый массив его длиной, поэтому вы получите, например, ["Enter sandman", 2] для "Enter sandman".

Если вам нужен результат как хеш, вы можете вызвать to_h для результата илиоберните Hash[ ] вокруг него.

11 голосов
/ 08 октября 2010
list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}
9 голосов
/ 07 октября 2010

Еще один дубль:

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

5 голосов
/ 08 октября 2010

Группировка и сортировка набора данных неизвестного размера в 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
0 голосов
/ 27 октября 2018

Поздно, но чистый ответ у меня,

l = list.group_by(&:titleize)
l.merge(l) { |k,v| l[k] = v.count }

Примечание. Если нам нужны уникальные ключи, т.е. без titleize, замените их на itself

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...