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 个条目(不仅仅是第一个(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

该解决方案在简洁方面并不优雅,但它具有更好的时间复杂度。换句话说,对于大量散列,它应该执行得更快。

您需要安装“算法” 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 回答
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 回答
1

从 Ruby 2.2.0 开始,max_by需要一个额外的参数,让您请求一定数量的顶级元素,而不仅仅是获取一个。使用这个,我们可以改进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 回答