2012-06-19 39 views
10

Hey Tôi có một mảng trong đó mỗi phần tử là một băm có chứa một vài giá trị và một số đếm.Lấy các phần tử n hàng đầu từ mảng ruby ​​của các giá trị băm

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

tôi có thể sắp xếp các mảng bằng cách đếm như sau:

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

Bây giờ tôi muốn để có thể lấy các mục n hàng đầu dựa trên số lượng (không chỉ đầu tiên (n)) Có một cách thanh lịch để làm điều này? Vì vậy, ví dụ, hãy n = 1 tôi mong đợi một tập kết quả.

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

kể từ khi tôi yêu cầu tất cả các mục có số điểm cao nhất .. nếu tôi hỏi cho top 2 điểm cao nhất tôi muốn có được

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

Trả lời

24

Enumerable#group_by để giải cứu (như thường lệ):

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

Hầu hết công việc được thực hiện bởi group_by. Các sort_by chỉ đơn giản là dòng những thứ lên để first(2) sẽ chọn ra các nhóm bạn muốn. Sau đó, map với last sẽ trích xuất số lượng/tên băm mà bạn đã bắt đầu và số flatten cuối cùng sẽ làm sạch phần thừa thừa trên mảng.

+0

Tuyệt vời. Cảm ơn rất nhiều vì đã giúp đỡ. –

2

Giải pháp này không thanh lịch về mặt ngắn gọn nhưng có độ phức tạp cao hơn. Nói cách khác, nó nên thực hiện nhanh hơn rất nhiều cho một số lượng rất lớn của băm.

Bạn sẽ cần phải cài đặt "algorithms" đá quý để sử dụng các cấu trúc dữ liệu Heap:

Heaps là một cấu trúc dữ liệu hiệu quả khi bạn cần phải tìm ra các yếu tố lớn nhất hoặc nhỏ nhất trong một nhóm. Loại heap đặc biệt này là optimal nếu giá trị của "n" nhỏ hơn nhiều so với tổng số cặp.

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

tokland a.k.a Arnau Sánchez là một trong những nhà phát triển ROR tốt nhất mà tôi tìm thấy trên SO cho đến nay. :) Câu trả lời của bạn đã giúp tôi có được kết quả mong muốn bằng cách sử dụng băm ruby. Cảm ơn. – LearningROR

2

Bắt đầu từ trong Ruby 2.2.0, max_by có một đối số bổ sung mà cho phép bạn yêu cầu một số lượng nhất định các yếu tố đầu thay vì chỉ nhận được một. Sử dụng này, chúng tôi có thể cải thiện trên mu quá ngắn 's câu trả lời

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

Các tài liệu không nói nếu mảng được trả về bởi max_by được sắp xếp. Nếu điều đó hóa ra là đúng mặc dù, chúng tôi chỉ có thể sử dụng reverse trong bước cuối cùng thay vì sắp xếp.

Các vấn đề liên quan