【问题标题】:Ruby: How to group a Ruby array?Ruby:如何对 Ruby 数组进行分组?
【发布时间】:2010-10-07 18:48:55
【问题描述】:

我有一个 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"]

我想要一个包含如下计数的列表:

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

所以理想情况下,我想要一个哈希值,它会给我计数并注意我有Enter Sandmanenter sandman,所以我需要它不区分大小写。我很确定我可以循环通过它,但有没有更清洁的方法?

【问题讨论】:

    标签: ruby-on-rails ruby


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

    group by 创建从专辑名称的capitalized 版本到包含list 中与其匹配的所有字符串的数组的哈希(例如"Enter sandman" => ["Enter Sandman", "Enter sandman"])。 map 然后用它的长度替换每个数组,所以你得到例如["Enter sandman", 2]"Enter sandman"

    如果您需要将结果作为哈希,您可以在结果上调用 to_h 或将 Hash[ ] 包裹起来。

    【讨论】:

      【解决方案2】:
      list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}
      

      【讨论】:

        【解决方案3】:

        另一种说法:

        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}
        

        正如我所说,您可能更喜欢titlecase

        【讨论】:

        • 这种情况下不需要使用Hash.new的块形式。所以你可以做h = Hash.new(0)
        【解决方案4】:

        在 Ruby 中对未知大小的数据集进行分组和排序应该是最后的选择。这是最好留给 DB 的家务活。通常,像您这样的问题可以使用COUNTGROUP BYHAVINGORDER BY 子句的组合来解决。幸运的是,rails 为此类用例提供了count 方法。

        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
        

        【讨论】:

          【解决方案5】:

          从 Ruby 2.7 开始,您可以使用 Enumerable#tally

          list.tally
          # => {"Nothing else Matters"=>1, "Enter sandman"=>1, "Enter Sandman"=>1, "Master of Puppets"=>3}
          

          【讨论】:

            【解决方案6】:

            我有迟到但干净的答案,

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

            注意:如果我们确实需要唯一键,即没有 titleize,则将其替换为 itself

            【讨论】:

              猜你喜欢
              • 2010-11-16
              • 1970-01-01
              • 1970-01-01
              • 2017-06-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-10-14
              • 1970-01-01
              相关资源
              最近更新 更多