2010-12-18 11 views
16

I tienen una matriz de objetosOrdenación de un conjunto basado en un atributo que puede ser nula en algunos elementos

[<#a star=1 val=1>, <#a star=nil val=3> , <#a star=2 val=2>] 

necesito la matriz a ser ordenados por el tiempo, a continuación, por val

[ <#a star=2 val=2>, <#a star=1 val=1>, <#a star=nil val=3> ] 

pero al usar sort_by arroja un error porque el tiempo es nulo.

estoy usando una manera fea para ordenar este momento, pero estoy seguro de que es una buena manera de hacerlo

starred=[] 
@answers.each {|a| (starred << a) if a.starred } 
@[email protected] 
starred=starred.sort_by {|a| a.starred }.reverse 
@[email protected] 

Respuesta

31
starred.sort_by { |a| [a ? 1 : 0, a] } 

Cuando se tiene que comparar dos elementos, que compara una arrays . Cuando Ruby compara matrices (llama al método ===), compara el primer elemento y va al segundo elemento solo si el primero es igual. ? 1 : 0 garantiza que tendremos Fixnum como primer elemento, por lo que no debería haber ningún error.

Si lo hace ? 0 : 1, nil aparecerá al final de la matriz en lugar de comenzar.
Aquí se muestra un ejemplo:

irb> [2, 5, 1, nil, 7, 3, nil, nil, 4, 6].sort_by { |i| [i ? 1 : 0, i] } 
=> [nil, nil, nil, 1, 2, 3, 4, 5, 6, 7] 

irb> [2, 5, 1, nil, 7, 3, nil, nil, 4, 6].sort_by { |i| [i ? 0 : 1, i] } 
=> [1, 2, 3, 4, 5, 6, 7, nil, nil, nil] 
7

si desea que el Nils aparezcan primero (cero equivalente):

@answers.sort_by { |a| a.star or 0 }

Si desea hacer que aparecen último, se puede reemplazar el cero con un Max Int, pero se siente demasiado hacky. Esto podría ser mejor:

@answers.select(&:starred?).sort_by(&:star) + @answers.reject(&:starred?)

La respuesta proporcionada por Nakilon es brillante, aunque básicamente estás clasificar en dos ocasiones, en dos atributos diferentes. Para la mayoría de las situaciones, probablemente sea suficiente.

+3

Gracias @ Amin-ariana, su solución funcionó para mí y creo que es más fácil de leer. – monteirobrena

+1

Esto no se comporta como el código inicial de OP para valores negativos como '-5' – Nakilon

0

sólo tiene que utilizar value.to_i

starred.sort_by { |a| a.to_i }.reverse 
Cuestiones relacionadas