Ordinare un array di oggetti in Ruby per attributo dell'oggetto?


129

Ho una serie di oggetti in Ruby on Rails. Voglio ordinare l'array in base a un attributo dell'oggetto. È possibile?

Risposte:


223

Consiglio invece di usare sort_by:

objects.sort_by {|obj| obj.attribute}

Soprattutto se l'attributo può essere calcolato.

O un approccio più conciso:

objects.sort_by(&:attribute)

81
O la versione abbreviata:objects.sort_by(&:attribute)
Nikola

3
oggetti ancora più brevi.sort_by &: attribute
jasin_89

1
In caso di problemi con l'ordinamento separato di lettere maiuscole e minuscole, è possibile utilizzareobjects.sort_by { |obj| obj.attribute.downcase }
campeterson

1
Qualche idea di come questo si confronta con sort!(ad esempio velocità, ecc.)?
Joshua Pinter


35

Sì, utilizzarlo Array#sort!è facile.

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

Grazie amico, ma non ha funzionato per me, ho una serie di oggetti. In quale uno degli attributi dell'oggetto viene creato_at. Voglio ordinarlo con questo campo. quindi ho fatto @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} ma senza fortuna per me puoi aiutare .... ??

4
Esiste un metodo created_at per accedere all'attributo @created_at? Che tipo di oggetto è @created_at? Definisce <=>? Che tipo di errori stai riscontrando? ecc. ecc. fino alla nausea. In altre parole, abbiamo bisogno di più dettagli di "ma non ho fortuna".
rampion

funziona se fai myarray = myarray.sort {...} senza "!"
DoruChidean

@Doru Sì, anche quello funziona, ma perché dovresti farlo? È meno diretto e meno efficiente. Da utilizzare sortse si desidera conservare l'originale e assegnare il risultato a un oggetto diverso; altrimenti, utilizzare la variante sul posto, sort!. Infatti, sortchiama sort!internamente, dopo aver copiato l'oggetto originale.
Konrad Rudolph

1
@Doru Deve esserci un errore da qualche altra parte nel codice, posso garantirti al 100% che sort!funzionerà perfettamente e farai sempre (!) La stessa cosa di quello che hai scritto.
Konrad Rudolph,

27

Ordine ascendente :

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

o

objects_array.sort_by{ |obj| obj.attribute }

Ordine decrescente :

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

o

objects_array.sort_by{ |obj| obj.attribute }.reverse

20

nel caso in cui sia necessario ordinare per due attributi, dove il primo è più importante del secondo (significa prendere in considerazione i secondi argomenti solo se i primi argomenti sono uguali), allora potresti fare così

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

o in caso di array di array

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

14

Puoi rendere ordinabile qualsiasi classe sovrascrivendo il metodo <=>:

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

Ora un array di oggetti Person sarà ordinabile su 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 funziona bene, come pubblicato sopra:

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

MA, devi assicurarti che l' <=>operatore sia implementato per quell'attributo. Se è un tipo di dati nativo di Ruby, questo non è un problema. Altrimenti, scrivi la tua implementazione che restituisca -1 se a <b, 0 se sono uguali e 1 se a> b.


10

Più elegante objects.sort_by(&:attribute), puoi aggiungere un .reversese devi cambiare l'ordine.



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

2
Ci sono molte risposte identiche pubblicate nel 2009. Non c'è bisogno di aggiungerne un'altra.
Interjay

2
Non utilizzare sortquando si ordinano oggetti che non possono essere confrontati direttamente. Se devi accedere agli attributi o eseguire un calcolo per ottenere il valore da confrontare, usa sort_by. Sarà molto più veloce.
Tin Man
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.