views:

86

answers:

4

I have a 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"]

and i want a list with the count like this

Nothing Else Matters => 1
Enter sandman => 2
Master of Puppets => 3

So ideally i want a hash that will give me the count and notice how i have Enter Sandman and enter sandman so i need it case insensitive..i am pretty sure i can loop through it but is there a clean way

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

The group by creates a hash from the capitalized version of an album name to an array containing all the strings in list that match it (e.g. "Enter sandman" => ["Enter Sandman", "Enter sandman"]). The map then replaces each array with its length, so you get e.g. ["Enter sandman", 2] for "Enter sandman".

If you need the result to be a hash, you can wrap a Hash[ ] around it.

sepp2k
Instead of `capitalize`, there's a `titlecase` snippet here: http://snippets.dzone.com/posts/show/294
glenn jackman
+3  A: 

Another take:

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}

As I commented, you might prefer titlecase

glenn jackman
In this case you don't need to use the block form of Hash.new. So you can just do `h = Hash.new(0)`.
sepp2k
+1  A: 

Grouping and sorting of a data set of unknown size in Ruby, should be a choice of last resort OR of masochists. This is a chore best left to DB. Typically problems like yours is solved using a combination of COUNT, GROUP BY, HAVING and ORDER BY clauses. Fortunately, rails provides a count method for such use cases.

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