こういうのはまだ出ていないみたいなので。集計したカウント(重複を排除後、ソート)本位にループを回します。ポイントは Hash#select で同じ順位の要素を集めてまとめて処理していること、でしょうか。
ary = %w(foo bar foo baz foo bar qux foo bar qux quux) n = 3 count = Hash.new{0} ary.each { |x| count[x] += 1 } i = 1 count.values.uniq.sort.reverse_each do |c| puts "#{i} 位:" count.select{ |k,v| v == c }.each{ |k,v| puts "- #{k}"; i += 1 } break if i > n end
| ary n count i | ary := #(foo bar foo baz foo bar qux foo bar qux quux). n := 3. count := Dictionary new. ary do: [:x | count at: x put: (count at: x ifAbsent: [0]) + 1]. i := 1. count values asSet asSortedArray reverseDo: [:c | | assocs | Transcript cr; show: ('{1} 位:' format: {i}). assocs := count associationsSelect: [:assoc | assoc value == c ]. assocs keysDo: [:k | Transcript cr; show: ('- {1}' format: {k}). i := i + 1]. i > n ifTrue: [^self] ]
さらに集計作業ではお定まりの a Bag 版も。ランク表示のほうは、少し趣向を変えて #inject:into: を使ってみました。
| ary n count i | ary := #(foo bar foo baz foo bar qux foo bar qux quux). n := 3. count := ary asBag sortedCounts. count := count select: [:assoc | assoc key >= (count at: n) key]. World findATranscript: nil. i := 0. count inject: nil into: [:prev :assoc | (prev isNil or: [prev key > assoc key]) ifTrue: [Transcript cr; show: (i := i + 1) printString, ' 位:']. Transcript cr; show: '- ', assoc value. assoc]