9

ちょっと、各要素がいくつかの値とカウントを含むハッシュである配列があります。

result = [
           {"count" => 3,"name" => "user1"}, 
           {"count" => 10,"name" => "user2"}, 
           {"count" => 10, "user3"},
           {"count" => 2, "user4"}
         ]

次のように、配列をカウントでソートできます。

result = result.sort_by do |r|
  r["count"]
end

ここで、カウントに基づいて上位 n エントリを取得できるようにしたい (first(n) だけでなく) これを行うエレガントな方法はありますか? 例として、 n = 1 とすると、結果セットが期待できます。

[{"count" => 10,"name" => "user2"}, {"count" => 10, "user3"}]

最高スコアのすべてのエントリを求めたので..上位2つの最高スコアを求めた場合、私は得るでしょう

 [{"count" => 10,"name" => "user2"}, {"count" => 10, "user3"}, {"count" => 3, "user1"}]
4

4 に答える 4

24

Enumerable#group_by救助に(いつものように):

result.group_by { |r| r["count"] }
      .sort_by  { |k, v| -k }
      .first(2)
      .map(&:last)
      .flatten

ほとんどの作業は によって行われますgroup_by。はsort_by単純に並べて、必要なfirst(2)グループを選択します。次にmapwithlastは、最初に使用したカウント/名前ハッシュを抽出し、最終的flattenに残りの余分な配列をクリーンアップします。

于 2012-06-19T05:46:00.513 に答える
2
new_result = result.
  sort_by { |r| -r["count"] }.
  chunk { |r| r["count"] }.
  take(2).
  flat_map(&:last)

#=> [{"count"=>10, "name"=>"user3"}, 
#    {"count"=>10, "name"=>"user2"}, 
#    {"count"=> 3  "name"=>"user1"}]
于 2012-06-19T10:39:00.917 に答える
2

このソリューションは、簡潔であるという点でエレガントではありませんが、時間の複雑さは優れています。言い換えれば、ハッシュの数が非常に多い場合は、はるかに高速に実行する必要があります。

Heap データ構造を使用するには、 「algorithms」 gemをインストールする必要があります。

ヒープは、グループ内の最大または最小の要素を見つける必要がある場合に効率的なデータ構造です。この特定のタイプのヒープは、「n」の値がペアの総数よりもはるかに小さい場合に最適です。

require 'algorithms'
def take_highest(result,n)
  max_heap = Containers::Heap.new(result){|x,y| (x["count"] <=> y["count"]) == 1}
  last = max_heap.pop
  count = 0
  highest = [last]
  loop do   
    top = max_heap.pop
    break if top.nil?
    count += (top["count"] == last["count"] ? 0 : 1)
    break if count == n
    highest << top
    last = top
  end
  highest
end
于 2012-06-19T09:03:46.990 に答える
1

Ruby 2.2.0 から、max_by1 つ取得するだけでなく、特定の数の最上位要素を要求できる追加の引数を取ります。これを使用して、 mu is too shortの答えを改善できます

result = [
           {count: 3, name: 'user1'},
           {count: 10, name: 'user2'},
           {count: 10, name: 'user3'},
           {count: 2, name: 'user4'}
         ]
p result.group_by { |r| r[:count] }
      .max_by(2, &:first)
      .flat_map(&:last)
      .sort_by { |r| -r[:count] }
# => [{:count=>10, :name=>"user2"}, {:count=>10, :name=>"user3"}, {:count=>3, :name=>"user1"}]

max_byドキュメントには、返された配列がソートされているかどうかは記載されていません。ただし、それが真実であることが判明した場合はreverse、並べ替えの代わりに最後のステップで使用できます。

于 2014-09-26T05:12:33.963 に答える