Mam tablicę obiektów w Ruby on Rails. Chcę posortować tablicę według atrybutu obiektu. Czy to możliwe?
Mam tablicę obiektów w Ruby on Rails. Chcę posortować tablicę według atrybutu obiektu. Czy to możliwe?
Odpowiedzi:
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)
objects.sort_by { |obj| obj.attribute.downcase }
sort!
(np. Prędkość itp.)?
Tak, korzystanie z Array#sort!
tego jest łatwe.
myarray.sort! { |a, b| a.attribute <=> b.attribute }
<=>
? Jakie błędy otrzymujesz? etc, etc, ad nauseum. Innymi słowy, potrzebujemy więcej szczegółów niż „ale nie mam szczęścia”.
sort
jeśli chcesz zachować oryginał i przypisać wynik do innego obiektu; w przeciwnym razie, należy użyć wariantu w miejscu, sort!
. W rzeczywistości sort
wywołuje sort!
wewnętrznie po skopiowaniu oryginalnego obiektu.
sort!
będzie działać dobrze i zawsze (!) Rób to samo, co napisałeś.
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
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] }
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" ]
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.
Bardziej elegancki objects.sort_by(&:attribute)
, możesz dodać, .reverse
jeśli chcesz zmienić kolejność.
@model_name.sort! { |a,b| a.attribute <=> b.attribute }
sort
gdy 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.
objects.sort_by(&:attribute)