【问题标题】:ruby: how to find non-unique elements in array and print each with number of occurrences?ruby:如何在数组中查找非唯一元素并打印每个元素的出现次数?
【发布时间】:2013-03-07 23:51:03
【问题描述】:

我有

a = ["a", "d", "c", "b", "b", "c", "c"]

并且需要打印类似的东西(按出现次数降序排列):

c:3
b:2

我了解第一部分(发现非唯一)是:

b = a.select{ |e| a.count(e) > 1 }
=> ["c", "b", "b", "c", "c"] 

puts b.select{|e, c| [e, a.count(e)] }.uniq

c
b

如何输出每个非唯一且出现次数向后排序?

【问题讨论】:

    标签: ruby arrays


    【解决方案1】:
    puts a.uniq.
           map { | e | [a.count(e), e] }.
           select { | c, _ | c > 1 }.
           sort.reverse.
           map { | c, e | "#{e}:#{c}" }
    

    【讨论】:

    • 非常优雅! '_'代表什么?我以前没见过。
    • @RichardBrown:一个变量名,通常表示未使用。
    • 您也可以在未使用的变量名称前使用下划线,例如_temporary。它具有相同的目的,但更具描述性。
    • 目的不一样。 _ 是 Ruby 中的一个特殊变量名(继承自 Perl),许多方法默认写入该变量名。 _temporary 或以_... 开头的任何其他变量不属于该类别,而是普通变量列表中的独立变量。
    • 我知道_ 也提供special purpose,但在这种情况下,它被用作分配但未使用的变量,为了在这种情况下抑制warning ruby generates,这两个选项服务于我相信的相同目的。
    【解决方案2】:

    group_by 方法经常用于此目的:

    a.group_by{ |i|一世 } { “一个” => [ [0] “一” ], “d” => [ [0] "d" ], "c" => [ [0] "c", [1] "c", [2] "c" ], "b" => [ [0] "b", [1] “乙” ] }

    我喜欢:

    a.group_by{ |i| i }.each_with_object({}) { |(k,v), h| h[k] = v.size } { “一” => 1, "d" => 1, "c" => 3, "b" => 2 }

    或者:

    哈希[a.group_by{ |i| i }.map{ |k,v| [k, v.size] }] { “一” => 1, "d" => 1, "c" => 3, "b" => 2 }

    其中一个可能会抓挠你的痒。从那里你可以使用一个小测试来减少结果:

    哈希[a.group_by{ |i| i }.map{ |k,v| v.size > 1 && [k, v.size] }] { "c" => 3, "b" => 2 }

    如果您只想打印信息,请使用:

    将 a.group_by{ |i| i }.map{ |k,v| "#{k}: #{v.size}" } 一个:1 d: 1 三:3 乙:2

    【讨论】:

    • group_by{|i| i} 现在可以表示为group_by(&:itself)
    【解决方案3】:

    怎么样:

    a.sort.chunk{|x| a.count(x)}.sort.reverse.each do |n, v|
      puts "#{v[0]}:#{n}" if n > 1
    end
    

    【讨论】:

      【解决方案4】:

      我个人喜欢这个解决方案:

       a.inject({}) {|hash, val| hash[val] ||= 0; hash[val] += 1; hash}.
         reject{|key, value| value == 1}.sort.reverse.
         each_pair{|k,v| puts("#{k}:#{v}")}
      

      【讨论】:

        【解决方案5】:

        从 Ruby 2.7 开始,您可以使用 Enumerable#tally 和编号的块参数:

        a = ["a", "d", "c", "b", "b", "c", "c"]
        puts a.tally.filter { _2 > 1 }.sort_by { -_2 }.map &:first
        

        在这里,Enumerable#tally 返回一个类似于{ 'a' => 1, 'b' => 2, ... } 的哈希,然后您必须对其进行过滤和排序。排序后,哈希将折叠为嵌套数组,例如[['b', 2], ...]。最后一步是获取每个数组元素的第一个参数,使用&:first

        【讨论】:

          【解决方案6】:
          a.reduce(Hash.new(0)) { |memo,x| memo[x] += 1; memo } # Frequency count.
            .select { |_,count| count > 1 } # Choose non-unique items.
            .sort_by { |x| -x[1] } # Sort by number of occurrences descending.
          # => [["c", 3], ["b", 2]]
          

          还有:

          a.group_by{|x|x}.map{|k,v|[k,v.size]}.select{|x|x[1]>1}.sort_by{|x|-x[1]}
          # => [["c", 3], ["b", 2]]
          

          【讨论】:

            【解决方案7】:

            这会给你一个带有element => occurrences的哈希:

            b.reduce(Hash.new(0)) do |hash, element|
              hash[element] += 1
              hash
            end
            

            【讨论】:

            • 块可以放得更优雅一点:hash.update(element => hash[element] + 1)
            【解决方案8】:
            puts a.uniq.
                 map { |e| a.count(e) > 1 ? [e, a.count(e)] : nil }.compact.
                 sort { |a, b| b.last <=> a.last }
            

            【讨论】:

            • @undur_gongor 我不认为是这样,但这与拥有a.uniq 相同...无论如何,我在代码中也保留了 uniq 值,这对问题很不利我修好了。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-01
            • 2018-01-18
            • 2015-03-07
            • 2021-03-16
            相关资源
            最近更新 更多