Sortowanie tablicy obiektów w Rubim według atrybutu obiektu?

128

Mam tablicę obiektów w Ruby on Rails. Chcę posortować tablicę według atrybutu obiektu. Czy to możliwe?

Blaszany Człowiek
źródło

Odpowiedzi:

222

Zamiast tego polecam użycie sort_by:

objects.sort_by {|obj| obj.attribute}

Zwłaszcza jeśli atrybut można obliczyć.

Lub bardziej zwięzłe podejście:

objects.sort_by(&:attribute)
Scott
źródło
81
Albo wersja skrócona:objects.sort_by(&:attribute)
Nikola
3
jeszcze więcej krótszych obiektów.
sort_by
1
Jeśli masz problemy z oddzielnym sortowaniem wielkich i małych liter, możesz użyćobjects.sort_by { |obj| obj.attribute.downcase }
campeterson
1
Masz jakiś pomysł, jak to się wypada sort!(np. Prędkość itp.)?
Joshua Pinter,
Enumerable # sort_by docs
Matt R. Wilson,
35

Tak, korzystanie z Array#sort!tego jest łatwe.

myarray.sort! { |a, b|  a.attribute <=> b.attribute }
Konrad Rudolph
źródło
Dzięki kolego, ale mi się nie udało, mam tablicę obiektów. W którym jeden z atrybutów obiektu jest tworzony_at. Chcę to posortować za pomocą tego pola. tak zrobiłem @ comm_bytes.sort! {| a, b | a.created_at <=> b.created_at} ale nie mam szczęścia, czy możesz pomóc .... ??
4
Czy istnieje metoda created_at, aby uzyskać dostęp do atrybutu @created_at? Jakim obiektem jest @created_at? Czy to definiuje <=>? Jakie błędy otrzymujesz? etc, etc, ad nauseum. Innymi słowy, potrzebujemy więcej szczegółów niż „ale nie mam szczęścia”.
rampion
działa, jeśli zrobisz myarray = myarray.sort {...} bez "!"
DoruChidean
@Doru Tak, to też działa, ale dlaczego miałbyś to zrobić? Jest mniej bezpośredni i mniej wydajny. Użyj, sortjeśli chcesz zachować oryginał i przypisać wynik do innego obiektu; w przeciwnym razie, należy użyć wariantu w miejscu, sort!. W rzeczywistości sortwywołuje sort!wewnętrznie po skopiowaniu oryginalnego obiektu.
Konrad Rudolph
1
@Doru Gdzieś indziej w kodzie musi być błąd, mogę w 100% zagwarantować, że sort!będzie działać dobrze i zawsze (!) Rób to samo, co napisałeś.
Konrad Rudolph
27

Rosnąco :

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

lub

objects_array.sort_by{ |obj| obj.attribute }

Kolejność malejąca :

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

lub

objects_array.sort_by{ |obj| obj.attribute }.reverse
shiva kumar
źródło
20

w przypadku, gdy potrzebujesz sortowania według dwóch atrybutów, gdzie pierwszy jest ważniejszy niż drugi (oznacza wzięcie pod uwagę drugich argumentów tylko wtedy, gdy pierwsze argumenty są równe), możesz to zrobić

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

lub w przypadku tablicy tablic

myarray.sort{ |a,b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] }
bumbu
źródło
14

Możesz ustawić dowolną klasę jako sortowalną, zastępując metodę <=>:

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

Teraz tablica obiektów Person będzie możliwa do sortowania według 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
źródło
10

Array # sort działa dobrze, jak napisano powyżej:

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

ALE musisz się upewnić, że <=>operator jest zaimplementowany dla tego atrybutu. Jeśli jest to natywny typ danych Ruby, nie stanowi to problemu. W przeciwnym razie napisz własną implementację, która zwraca -1, jeśli a <b, 0, jeśli są równe i 1, jeśli a> b.

cjs
źródło
10

Bardziej elegancki objects.sort_by(&:attribute), możesz dodać, .reversejeśli chcesz zmienić kolejność.

Noah Davis
źródło
-2
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
Harisankar PS
źródło
2
W 2009 roku opublikowano wiele identycznych odpowiedzi. Nie ma potrzeby dodawania kolejnej.
interjay
2
Nie używaj, sortgdy sortujesz obiekty, których nie można bezpośrednio porównać. Jeśli musisz uzyskać dostęp do atrybutów lub wykonać obliczenia, aby uzyskać wartość do porównania, użyj sort_by. Będzie dużo szybciej.
Tin Man