2010-10-07 14 views
41

Mam tablicy RubyRuby: Jak pogrupować tablicę 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"] 

i chcę listy z hrabiów tak:

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

Więc idealnie chcę hash, które dadzą mi licznik i zauważyć, jak mam Enter Sandman i enter sandman, więc potrzebuję go niewrażliwego na wielkość liter. Jestem prawie pewien, że mogę przechodzić przez to, ale czy istnieje czystszy sposób?

Odpowiedz

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

grupa o mieszania tworzy z wersji capitalize d z nazwy album do macierzy zawierającej wszystkie sznurki list które go (np "Enter sandman" => ["Enter Sandman", "Enter sandman"]) zgodne. map następnie zamienia każdą tablicę na swoją długość, dzięki czemu otrzymasz np. ["Enter sandman", 2] dla "Enter sandman".

Jeśli chcesz, aby wynik był mieszania, możesz zadzwonić pod numer to_h lub owinąć wokół niego Hash[ ].

+2

Zamiast 'capitalize', tam' titlecase' snippet tutaj: http://snippets.dzone.com/posts/show/294 –

7

Innym odbioru:

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} 

Jak zauważył, może wolisz titlecase

+5

W tym przypadku nie trzeba używać blokowa forma Hash.new. Więc możesz po prostu zrobić 'h = Hash.new (0)'. – sepp2k

+0

Ta odpowiedź wpadła mi w oko, ponieważ jest prosta, czytelna i elastyczna. – thekingoftruth

5

grupowanie i sortowanie zbioru danych o nieznanej wielkości w Ruby powinien być wybór ostateczności. To jest chore najlepiej pozostawić do DB. Zazwyczaj problemy takie jak Twoje rozwiązywane są przy użyciu kombinacji klauzul COUNT, GROUP BY, i ORDER BY. Na szczęście szyny zapewniają metodę count dla takich przypadków użycia.

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} 
Powiązane problemy