J'ai un tableau de rubis
> 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"]
et je veux une liste avec les comptes comme ceci:
{"Nothing Else Matters" => 1,
"Enter Sandman" => 2,
"Master of Puppets" => 3}
Donc, idéalement, je veux un hachage qui me donnera le compte et remarquera comment j'ai Enter Sandman
et enter sandman
donc j'en ai besoin de la casse. Je suis à peu près sûr de pouvoir le parcourir en boucle, mais existe-t-il un moyen plus propre?
list.group_by(&:capitalize).map {|k,v| [k, v.length]}
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]]
Le groupe by crée un hachage à partir de la version capitalize
d d'un nom d'album dans un tableau contenant toutes les chaînes de list
qui lui correspondent (par exemple "Enter sandman" => ["Enter Sandman", "Enter sandman"]
). La map
remplace ensuite chaque tableau par sa longueur. Vous obtenez par exemple, par exemple. ["Enter sandman", 2]
pour "Enter sandman"
.
Si vous souhaitez que le résultat soit un hachage, vous pouvez appeler to_h
sur le résultat ou envelopper un Hash[ ]
autour de celui-ci.
list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}
Une autre prise:
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}
Comme je l'ai commenté, vous pourriez préférer titlecase
Le regroupement et le tri d'un ensemble de données de taille inconnue dans Ruby doivent être un choix de dernier recours. C’est une tâche qu'il vaut mieux laisser à DB. Généralement, des problèmes comme le vôtre sont résolus à l'aide d'une combinaison de clauses COUNT
, GROUP BY
, HAVING
et ORDER BY
. Heureusement, Rails fournit une méthode count
pour de tels cas d'utilisation.
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
Réponse tardive mais nette que j'ai,
l = list.group_by(&:titleize)
l.merge(l) { |k,v| l[k] = v.count }
Remarque: si nous voulons des clés uniques, c'est-à-dire sans titleize
, alors remplacez-les par itself