1

配列内のアイテムの出現回数を繰り返しカウントし、実際のカウントとともに上位のアイテムを表示したいと思っています。私は次のようなコードを何度も書いてきましたが、これは繰り返し発生する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のモンキーパッチに移動できます…</p>

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メソッドを使用してこれを実現するためのよりエレガントな方法(入力を少なくするだけで十分)があるのではないかと思います。

4

3 に答える 3

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] 
于 2012-05-31T23:03:14.160 に答える
1

私が持っているコードは、それが得られるのと同じくらい簡潔であるように見えます。非モンキーパッチ方式に移行:

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
于 2012-06-06T16:42:16.303 に答える
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 を使用してください。

于 2012-05-31T23:05:55.783 に答える