从Ruby哈希数组值中获取前n个元素

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

现在我想根据计数(而不仅仅是 first(n))检索前 n 个条目。有一种优雅的方法可以做到这一点吗?

例如,假设 n = 1,我期望得到以下结果集。

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

因为我要求所有得分最高的条目.. 如果我要求前两个最高分数,我会得到

 [{"count" => 10,"name" => "user2"}, {"count" => 10, "user3"}, {"count" => 3, "user1"}]
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) 可以选择你想要的组。然后使用 maplast 提取您最初拥有的计数/名称哈希表,最终使用 flatten 清理额外剩余的数组。


2
这个解决方案在简洁性方面不够优雅,但时间复杂度更好。 换句话说,它应该在处理大量哈希时执行得更快。
你需要安装 "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

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"}]

tokland,又名Arnau Sánchez,是我在SO上找到的最好的ROR开发者之一。 :) 您的答案帮助我使用Ruby哈希获得了所需的结果。谢谢。 - user5084534

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而不是排序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接