2012-06-08 19 views
5

Decir que tengo un hash como:Ordenar hachís por la longitud de los valores contenidos

foo = { 
    :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array 
    :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array, 
    :blah => ['at'] # has a total str length of 2 characters inside of the array 
    # etc... 
} 

¿Cómo hago para clasificar este hash por la longitud total de cadena de los elementos contenidos en las matrices? El orden hash resultante en este caso debería ser: :blah, :bar, :baz

+1

¿Qué quiere decir con "clasificación de hash"? – nonowarn

+2

Imagina por un segundo que Ruby no puede ayudarte. ¿Qué harás entonces? – alf

+0

@alf Supongo que sería SOL ... ¿pero cómo me ayuda eso? –

Respuesta

11

que acababa de hacer esto:

Hash[foo.sort_by { |k, v| v.join.length }] 

Asumo que no está la intención del cambio de los valores Hash originales, simplemente volver a pedir ellos.

1
foo.sort_by { |_,v| v.reduce(:+).size } 
+0

Incluso 'reduce (: +)' es suficiente. Sin embargo, esto se ordena por cadena (alfabético), no por longitud de cadena. – Casper

+0

@Casper tienes razón. He editado la respuesta para usar la longitud de la cadena. –

3

Tradicionalmente, los hashes no están clasificadas, y por lo tanto no se puede ordenar. Los hashes de Ruby 1.9 están ordenados, pero el lenguaje no proporciona una manera fácil de reordenar los elementos. Al igual que en 1.8, la clasificación de un hash devuelve una matriz de pares: (. En realidad, 1,8 explotaría en que, debido a los símbolos no son comparables en 1.8, pero no importa)

{ c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ] 

Pero a medida Mientras esté bien con la lista de pares, puede ordenar un hash (o una matriz) por cualquier cosa que desee. Sólo tiene que utilizar sort_by y pasar un bloque que extrae la clave de ordenación, o utilizar un género con un bloque que hace la comparación:

foo.sort_by { |key, strings| strings.join.length } 

o, si lo desea los más largos primero:

foo.sort_by { |key, strings| -strings.join.length } 

Entonces, si está utilizando 1.9 y quieren convertir el resultado en un hash, puede hacerlo de este modo (gracias, Jörg W Mittag):

Hash[ foo.sort_by { |key, strings| strings.join.length } ] 

... que es la misma respuesta que d11wtq.

+0

'Hash :: []' toma exactamente el tipo de matrices de valor-clave que producen todos los demás métodos 'Hash', por lo tanto, si quiere' map' or' sort' or' sort_by' a 'Hash', usted simplemente ajuste toda la expresión en 'Hash [...]' para recuperar '' Hash'. –

1

Hash no garantiza el orden de las claves en su concepto. Pero en Ruby 1.9, Hash's key order is saved. Entonces puede usar el código en otras respuestas si usa 1.9.

Pero no recomiendo confiar en este comportamiento porque es un comportamiento implícito y temo cambios futuros. En su lugar, use el método que produce la entrada hash en orden de suma de longitud de cadenas.

def each_by_length(hash) 
    hash = hash.sort_by { |_, strs| strs.map(&:length).inject(0, &:+) } 
    hash.each do |k, v| 
    yield k, v 
    end 
end 
Cuestiones relacionadas