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


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)

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


35

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

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

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

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

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

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.


10

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



-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.