2012-01-17 11 views
20

tengo una matriz mulitdimensional así:Clasificación: Ordenar un array basado en múltiples condiciones en Ruby

[ 
    [name, age, date, gender] 
    [name, age, date, gender] 
    [..] 
] 

Me pregunto la mejor manera de solucionar esta matriz basada en múltiples condiciones ... Por ejemplo, ¿cómo ¿ordenaría basado en edadprimero y luego por su nombre?

me estaba metiendo con el método sort así:

array.sort { |a,b| [ a[1], a[0] ] <=> [ b[1], b[0] ] } 

Además de que yo no entiendo muy bien esta sintaxis, no estoy consiguiendo los resultados que cabe esperar. ¿Debo usar el método sort? ¿Debo comparar individualmente los resultados por mapping la matriz?

+1

posible duplicado de [ordenado una colección de objetos por número (más caros primero) y luego por carta (por orden alfabético)] (http: // stackoverflow.com/questions/2232470/sort-a-collection-of-objects-by-number-highest-first-then-by-letter-alphabeti) –

+1

@pruett: no hay falta de respeto por la respuesta de robbrit, pero debe considerar el seleccionado responda, no hay nada de malo en usar Enumerable # sort * excepto * cuando Enumerable # sort_by hace el trabajo. Esto puede ser engañoso para las personas que aterricen aquí. – tokland

+0

Posible duplicado de [Ruby ordenar por valores múltiples?] (Http://stackoverflow.com/questions/4309723/ruby-sort-by-multiple-values) – jtbandes

Respuesta

39

Usted debe siempre use sort_by para ordenar con llave. No solo es mucho más legible, también es mucho más más eficiente. Además, yo también preferiría usar unen desestructuración, de nuevo, para facilitar la lectura:

ary.sort_by {|name, age| [age, name] } 
+3

[enlace desestructurado] (http://stackoverflow.com/a/3952057/38765) –

11

Esto debería hacer el truco:

array.sort { |a,b| [ a[1], a[0] ] <=> [ b[1], b[0] ] } 

Entonces, ¿qué hace esto? Utiliza muchos modismos de Ruby.

  • Primero están los bloques, que son como devoluciones de llamada o funciones/clases anónimas en otros idiomas. El método sort de Array los usa para comparar dos elementos en función del valor de retorno del bloque. Puedes leer todo sobre ellos here.
  • Siguiente es el operador <=>. Devuelve -1 si el primer argumento es menor que el segundo, 0 si son iguales y 1 si el primero es mayor que el segundo. Cuando lo utiliza con matrices, comparará las matrices en cuanto a los elementos hasta que uno de ellos devuelva -1 o 1. Si las matrices son iguales, obtendrá 0.
+0

gran explicación ... gracias @robbrit. – pruett

+6

También podría usar 'sort_by {| a | [a [1], a [0]]} ', la construcción de todas esas matrices no es gratis. –

6

Según tengo entendido, usted desea pedir por edad, y luego, si más de un registro tiene la misma edad, organice ese subconjunto por su nombre.


Esto funciona para mí

people = [ 
     ["bob", 15, "male"], 
     ["alice", 25, "female"], 
     ["bob", 56, "male"], 
     ["dave", 45, "male"], 
     ["alice", 56, "female"], 
     ["adam", 15, "male"] 
    ] 

people.sort{|a,b| (a[1] <=> b[1]) == 0 ? (a[0] <=> b[0]) : (a[1] <=> b[1]) } 

# The sorted array is 

[["adam", 15, "male"], 
["bob", 15, "male"], 
["alice", 25, "female"], 
["dave", 45, "male"], 
["alice", 56, "female"], 
["bob", 56, "male"]] 

Lo que esto hace es comparar la edad primera, y si la edad es la misma (< => returs 0) se compara el nombre.

+0

muy bueno! Me gusta esa sintaxis – pruett

+0

¿Qué pasa si la edad es la misma y luego queremos ordenar el nombre en orden descendente? – inquisitive

+0

@Inquisitivo, entonces en ese caso, creo que cambiaría la "a" y la "b" en "(a [1] <=> b [1])" a la derecha. – user1515295

Cuestiones relacionadas