2010-10-07 11 views
41

Ich habe ein Array RubinRuby: Wie gruppiert man ein Ruby-Array?

> 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"] 

und ich möchte eine Liste mit den Zählungen wie folgt aus:

{"Nothing Else Matters" => 1, 
"Enter Sandman" => 2, 
"Master of Puppets" => 3} 

So ideal möchte ich einen Hash, der mir die Zählung und bemerken geben, wie ich Enter Sandman haben und enter sandman so brauche ich es case insensitive. Ich bin mir ziemlich sicher, dass ich es durchgehen kann, aber gibt es einen saubereren Weg?

Antwort

80
list.group_by(&:capitalize).map {|k,v| [k, v.length]} 
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]] 

Die Gruppe, die durch einen Hash erstellt aus der capitalize d Version eines Albumnamens an ein Array alle Fäden in list enthält, die es (z.B. "Enter sandman" => ["Enter Sandman", "Enter sandman"]) entsprechen. Die map ersetzt dann jedes Array mit seiner Länge, so erhalten Sie z.B. ["Enter sandman", 2] für "Enter sandman".

Wenn Sie möchten, dass das Ergebnis ein Hashwert ist, können Sie to_h auf das Ergebnis aufrufen oder ein Hash[ ] darum wickeln.

+2

Statt 'capitalize', dann ist es ein' titlecase' Schnipsel hier: http://snippets.dzone.com/posts/show/294 –

7

empfange ein anderer:

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} 

Als ich bemerkte, können Sie es vorziehen, titlecase

+5

In diesem Fall müssen Sie nicht die verwenden Blockform von Hash.new. Du kannst einfach 'h = Hash.new (0)' machen. – sepp2k

+0

Diese Antwort fiel mir auf, weil sie einfach, lesbar und flexibel ist. – thekingoftruth

5

Gruppierung und Sortierung eines Datensatzes von unbekannter Größe in Ruby sollte eine Auswahl der letzten Instanz sein. Das ist eine Aufgabe, die man der DB am besten lässt. Typischerweise werden Probleme wie das Ihre gelöst, indem eine Kombination von COUNT, GROUP BY, HAVING und ORDER BY Klauseln verwendet wird. Glücklicherweise bietet Rails ein count Verfahren für solche Anwendungsfälle.

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 
11
list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h} 
Verwandte Themen