我发现自己一再想要计算数组中项目的出现次数,并显示顶部项目及其实际数量。我已经编写了如下代码,这么多次我认为它是一种反复出现的RSI诱导模式:
hits = Hash[ array.group_by{|o|o}.map{|o,a|[o,a.length]}.sort_by{|o,ct|[-ct,o]} ]
require 'pp'
pp hits
我可以将它移动到Enumerable上的monkeypatch ......
module Enumerable
def counts(&blk)
blk ||= ->(o){o}
Hash[ group_by(&blk).map{|o,a| [o,a.length] }.sort_by{|o,ct| [-ct,o] } ]
end
end
a = %w[a b a b c d e g j a e c d k o k i l p a e c f d e a d e f s d v c ]
pp a.counts
#=> {"a"=>5,
#=> "d"=>5,
#=> "e"=>5,
#=> "c"=>4,
#=> "b"=>2,
#=> "f"=>2,
#=> "k"=>2,
#=> "g"=>1,
#=> "i"=>1,
#=> "j"=>1,
#=> "l"=>1,
#=> "o"=>1,
#=> "p"=>1,
#=> "s"=>1,
#=> "v"=>1}
...但我想知道使用核心Ruby方法是否有一种更优雅的方法来实现这一点(更少的输入就足够了)。
答案 0 :(得分:5)
ruby-1.9.2-p290 :041 > Hash[*[1,1,2,3,4,5,5,5].inject(Hash.new(0)) { |h,v| h[v] += 1; h }.sort_by{|k,v| v}.reverse.flatten]
=> {5=>3, 1=>2, 4=>1, 2=>1, 3=>1}
如果您希望根据不出现的情况对列表进行排名,请注意以下情况,
ruby-1.9.2-p290 :045 > [1,1,2,3,4,5,5,5].group_by{|x| x}.sort_by{|k, v| -v.size}.map(&:first)
=> [5, 1, 2, 4, 3]
答案 1 :(得分:1)
看起来我的代码就像它将要获得的一样简洁。转入非monkeypatching方法:
def count_items(enum,&blk)
blk ||= ->(o){o}
Hash[ enum.group_by(&blk).map{|o,a| [o,a.length] }.sort_by{|o,ct| [-ct,o] } ]
end
答案 2 :(得分:0)
没有提前排序,这对于高n来说可能很慢:
a = %w[a b a b c d e g j a e c d k o k i l p a e c f d e a d e f s d v c ]
a.each_with_object( {} ) {|e, h| h[e] ||= 0; h[e] += 1 }.sort_by {|o, ct| [-ct, o] }
如果您关心优雅,请在适当时使用#with_object / #each_with_object。