Classificando uma matriz de objetos em Ruby por atributo de objeto?

128

Eu tenho uma matriz de objetos em Ruby on Rails. Eu quero classificar a matriz por um atributo do objeto. É possível?

o homem de lata
fonte

Respostas:

222

Eu recomendo usar sort_by:

objects.sort_by {|obj| obj.attribute}

Especialmente se o atributo puder ser calculado.

Ou uma abordagem mais concisa:

objects.sort_by(&:attribute)
Scott
fonte
81
Ou a versão abreviada:objects.sort_by(&:attribute)
Nikola
3
ainda mais curto objects.sort_by &: atributo
jasin_89
1
Se você tiver problemas com maiúsculas e minúsculas que estão sendo classificados separadamente, você pode usarobjects.sort_by { |obj| obj.attribute.downcase }
campeterson
1
Alguma idéia de como isso se compara sort!(por exemplo, velocidade, etc.)?
Joshua Pinter
Enumerable # sort_by docs
Matt R. Wilson
35

Sim, Array#sort!é fácil usar isso.

myarray.sort! { |a, b|  a.attribute <=> b.attribute }
Konrad Rudolph
fonte
Thnx amigo, mas não funcionou para mim, eu tenho uma variedade de objetos. Em que um dos atributos do objeto é criado_at. Eu quero classificá-lo com este campo. então eu fiz @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} mas sem sorte para mim você pode ajudar .... ??
4
Existe um método created_at para acessar o atributo @created_at? Que tipo de objeto é @created_at? Isso define <=>? Que tipo de erros você está recebendo? etc, etc, ad nauseum. Em outras palavras, precisamos de mais detalhes do que "mas sem sorte para mim".
Rampion 20/05/09
funciona se você fizer myarray = myarray.sort {...} sem "!"
precisa saber é o seguinte
@ Doru Sim, isso funciona também, mas por que você faria isso? É menos direto e menos eficiente. Use sortse desejar preservar o original e atribuir o resultado a um objeto diferente; caso contrário, use a variante no local sort!,. De fato, sortchama sort!internamente, depois de copiar o objeto original.
Konrad Rudolph
1
@DuRu Deve haver um erro em outro lugar do código, posso garantir 100% de que você sort!irá funcionar bem e sempre (!) Fará a mesma coisa que você escreveu.
Konrad Rudolph
27

Ordem ascendente :

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

ou

objects_array.sort_by{ |obj| obj.attribute }

Ordem decrescente :

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

ou

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

caso você precise classificar por dois atributos, onde o primeiro é mais importante que o segundo (significa considerar os segundos argumentos apenas se os primeiros argumentos forem iguais), faça o seguinte

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

ou no caso de matriz de matrizes

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

Você pode classificar qualquer classe substituindo o 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

Agora, uma matriz de objetos Pessoa poderá ser classificada em 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" ]
user1182000
fonte
10

A matriz # sort funciona bem, conforme publicado acima:

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

MAS, você precisa garantir que o <=>operador esteja implementado para esse atributo. Se for um tipo de dados nativo do Ruby, isso não é um problema. Caso contrário, escreva sua própria implementação que retornará -1 se a <b, 0 se forem iguais e 1 se a> b.

cjs
fonte
10

Mais elegante objects.sort_by(&:attribute), você pode adicionar um .reversese precisar alterar o pedido.

Noah Davis
fonte
-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
Harisankar PS
fonte
2
Há muitas respostas idênticas postadas em 2009. Não há necessidade de adicionar outra.
interjay
2
Não use sortao classificar objetos que não podem ser comparados diretamente. Se você precisar acessar atributos ou fazer um cálculo para obter o valor para comparar o uso sort_by. Será muito mais rápido.
o homem de lata