ruby: how to find non-unique elements in array and print each with number of occurrences?

后端 未结 8 1431
轻奢々
轻奢々 2020-12-31 03:54

I have

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

and need to print something like (sorted descending by number of occurrences)

相关标签:
8条回答
  • 2020-12-31 04:02
    puts a.uniq.
           map { | e | [a.count(e), e] }.
           select { | c, _ | c > 1 }.
           sort.reverse.
           map { | c, e | "#{e}:#{c}" }
    
    0 讨论(0)
  • 2020-12-31 04:02
    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]]
    

    Also:

    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]]
    
    0 讨论(0)
  • 2020-12-31 04:04

    From Ruby 2.7, you can utilise Enumerable#tally and numbered block arguments:

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

    Here, Enumerable#tally returns a hash like { 'a' => 1, 'b' => 2, ... }, which you then have to filter and sort. After sorting, the hash would've collapsed to a nested array, e.g. [['b', 2], ...]. The last step is to take the first argument of each array element, using &:first.

    0 讨论(0)
  • 2020-12-31 04:06
    puts a.uniq.
         map { |e| a.count(e) > 1 ? [e, a.count(e)] : nil }.compact.
         sort { |a, b| b.last <=> a.last }
    
    0 讨论(0)
  • 2020-12-31 04:08

    The group_by method is used for this often:

    a.group_by{ |i| i }
    {
        "a" => [
            [0] "a"
        ],
        "d" => [
            [0] "d"
        ],
        "c" => [
            [0] "c",
            [1] "c",
            [2] "c"
        ],
        "b" => [
            [0] "b",
            [1] "b"
        ]
    }
    

    I like:

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

    Or:

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

    One of those might scratch your itch. From there you can reduce the result using a little test:

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

    If you just want to print the information use:

    puts a.group_by{ |i| i }.map{ |k,v| "#{k}: #{v.size}" }
    a: 1
    d: 1
    c: 3
    b: 2
    
    0 讨论(0)
  • 2020-12-31 04:18

    This will give you a hash with element => occurrences:

    b.reduce(Hash.new(0)) do |hash, element|
      hash[element] += 1
      hash
    end
    
    0 讨论(0)
提交回复
热议问题