2012-06-19 19 views
10

Hola, tengo una matriz donde cada elemento es un hash que contiene algunos valores y un recuento.Obtiene los primeros n elementos de la matriz de valores de hash Ruby

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

puedo ordenar la matriz mediante el recuento de la siguiente manera:

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

Ahora quiero ser capaz de recuperar las entradas de n superiores basados ​​en el recuento (no sólo la primera (n)) ¿Existe una manera elegante de hacer esto? Entonces, como ejemplo, supongamos que n = 1 esperaría un conjunto de resultados de.

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

ya pedí todas las entradas con la puntuación más alta .. si se lo pidiera para los mejores 2 puntuaciones más altas que tendría

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

Respuesta

24

Enumerable#group_by al rescate (como es habitual):

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

La mayor parte del trabajo se realiza por group_by. El sort_by simplemente alinea las cosas para que first(2) seleccione los grupos que desee. A continuación, map con last extraerá los hashes de recuento/nombre con los que comenzó y el flatten final limpiará las matrices restantes sobrantes.

+0

Excelente. Muchas gracias por la ayuda. –

2

Esta solución no es elegante en términos de ser conciso, pero tiene una mejor complejidad temporal. En otras palabras, debería ejecutarse mucho más rápido para una gran cantidad de hashes.

Usted tendrá que instalar la gema "algorithms" con el fin de utilizar la estructura de datos del montón:

Heaps son una estructura de datos eficaz cuando se necesita para encontrar los elementos más grandes o más pequeños en un grupo. Este tipo particular de montón es optimal si el valor de "n" es mucho menor que el número total de pares.

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 es uno de los mejores desarrolladores de ROR que encontré en SO hasta el momento. :) Tu respuesta me ayudó a obtener los resultados deseados usando hashes de ruby. Gracias. – LearningROR

2

Comenzando en Ruby 2.2.0, max_by toma un argumento adicional que le permite pedir un cierto número de elementos superior en lugar de simplemente conseguir uno. Usando esto, podemos mejorar en mu es demasiado corta 's respuesta

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

Los documentos no dicen si se ordena la matriz devuelta por max_by. Si eso resulta ser cierto, podríamos simplemente usar reverse en el último paso en lugar de ordenar.

Cuestiones relacionadas