¿Ordenar una matriz de objetos en Ruby por atributo de objeto?

128

Tengo una gran variedad de objetos en Ruby on Rails. Quiero ordenar la matriz por un atributo del objeto. ¿Es posible?

el hombre de hojalata
fuente

Respuestas:

222

Recomiendo usar sort_by en su lugar:

objects.sort_by {|obj| obj.attribute}

Especialmente si se puede calcular el atributo.

O un enfoque más conciso:

objects.sort_by(&:attribute)
Scott
fuente
81
O la versión abreviada:objects.sort_by(&:attribute)
Nikola
3
objetos aún más cortos.
ordenar_por
1
Si tiene problemas con las letras mayúsculas y minúsculas que se ordenan por separado, puede usarobjects.sort_by { |obj| obj.attribute.downcase }
campeterson
1
¿Alguna idea de cómo se compara esto sort!(por ejemplo, velocidad, etc.)?
Joshua Pinter
Enumerable # sort_by docs
Matt R. Wilson
35

Sí, usar Array#sort!esto es fácil.

myarray.sort! { |a, b|  a.attribute <=> b.attribute }
Konrad Rudolph
fuente
Thnx amigo, pero no funcionó para mí, tengo una gran variedad de objetos. En el que se crea uno de los atributos del objeto_at. Quiero ordenarlo con este campo. ¡así que hice @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} pero no hay suerte para mí, ¿puedes ayudarme ...?
44
¿Existe un método created_at para acceder al atributo @created_at? ¿Qué tipo de objeto es @created_at? ¿Se define <=>? ¿Qué tipo de errores tienes? etc, etc, ad nauseum. En otras palabras, necesitamos más detalles que "pero no suerte para mí".
rampion
funciona si haces myarray = myarray.sort {...} sin "!"
DoruChidean
@Doru Sí, eso también funciona, pero ¿por qué harías eso? Es menos directo y menos eficiente. Úselo sortsi desea conservar el original y asignar el resultado a un objeto diferente; de otro modo, utilizar la variante en el lugar, sort!. De hecho, sortllama sort!internamente, después de copiar el objeto original.
Konrad Rudolph
1
@Doru Debe haber un error en otra parte del código, puedo garantizarle al 100% que sort!funcionará bien y siempre (!) Hacer lo mismo que ha escrito.
Konrad Rudolph
27

Orden ascendente:

objects_array.sort! { |a, b|  a.attribute <=> b.attribute }

o

objects_array.sort_by{ |obj| obj.attribute }

Orden descendiente :

objects_array.sort! { |a, b|  b.attribute <=> a.attribute }

o

objects_array.sort_by{ |obj| obj.attribute }.reverse
shiva kumar
fuente
20

en caso de que necesite ordenar por dos atributos, donde el primero es más importante que el segundo (significa tener en cuenta los segundos argumentos solo si los primeros argumentos son iguales), entonces puede hacer esto

myarray.sort{ |a,b| (a.attr1 == b.attr1) ? a.attr2 <=> b.attr2 : a.attr1 <=> b.attr1 }

o en caso de una matriz de matrices

myarray.sort{ |a,b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] }
bumbu
fuente
14

Puede hacer que cualquier clase se pueda ordenar reemplazando el método <=>:

class Person

  attr_accessor :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def <=>(other)
    @last_name + @first_name <=> other.last_name + other.first_name
  end

end

Ahora se podrá ordenar una matriz de objetos Persona en last_name.

ar = [Person.new("Eric", "Cunningham"), Person.new("Homer", "Allen")]

puts ar  # => [ "Eric Cunningham", "Homer Allen"]  (Person objects!)

ar.sort!

puts ar  # => [ "Homer Allen", "Eric Cunningham" ]
usuario1182000
fuente
10

Array # sort funciona bien, como se publicó anteriormente:

myarray.sort! { |a, b|  a.attribute <=> b.attribute }

PERO, debe asegurarse de que el <=>operador esté implementado para ese atributo. Si es un tipo de datos nativo de Ruby, esto no es un problema. De lo contrario, escriba su propia implementación que devuelva -1 si a <b, 0 si son iguales y 1 si a> b.

cjs
fuente
10

Más elegante objects.sort_by(&:attribute), puede agregar un .reversesi necesita cambiar el orden.

Noah Davis
fuente
-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
Harisankar PS
fuente
2
Hay muchas respuestas idénticas publicadas en 2009. No es necesario agregar otra.
Interjay
2
No lo use sortcuando esté clasificando objetos que no se pueden comparar directamente. Si tiene que acceder a los atributos o hacer un cálculo para obtener el valor para comparar el uso sort_by. Será mucho más rápido
The Tin Man