Ruby: How to group a Ruby array?

后端 未结 6 1303
执念已碎
执念已碎 2020-12-28 12:17

I have a Ruby array

> list = Request.find_all_by_artist(\"Metallica\").map(&:song)
=> [\"Nothing else Matters\", \"Enter sandman\", \"Enter Sandman         


        
相关标签:
6条回答
  • 2020-12-28 12:22

    As of Ruby 2.7, you can use Enumerable#tally.

    list.tally
    # => {"Nothing else Matters"=>1, "Enter sandman"=>1, "Enter Sandman"=>1, "Master of Puppets"=>3}
    
    0 讨论(0)
  • 2020-12-28 12:33
    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 call to_h on the result or wrap a Hash[ ] around it.

    0 讨论(0)
  • 2020-12-28 12:33
    list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}
    
    0 讨论(0)
  • 2020-12-28 12:34

    Grouping and sorting of a data set of unknown size in Ruby should be a choice of last resort. 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
    
    0 讨论(0)
  • 2020-12-28 12:38

    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

    0 讨论(0)
  • 2020-12-28 12:42

    Late but clean answer I have,

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

    Note: If we do want unique keys i.e. without titleize, then replace it with itself

    0 讨论(0)
提交回复
热议问题