Sorting an array of objects in Ruby by object attribute?
RubySortingObjectRuby Problem Overview
I have an array of objects in Ruby on Rails. I want to sort the array by an attribute of the object. Is it possible?
Ruby Solutions
Solution 1 - Ruby
I recommend using sort_by instead:
objects.sort_by {|obj| obj.attribute}
Especially if attribute may be calculated.
Or a more concise approach:
objects.sort_by(&:attribute)
Solution 2 - Ruby
Yes, using Array#sort!
this is easy.
myarray.sort! { |a, b| a.attribute <=> b.attribute }
Solution 3 - Ruby
Ascending order :
objects_array.sort! { |a, b| a.attribute <=> b.attribute }
or
objects_array.sort_by{ |obj| obj.attribute }
Descending order :
objects_array.sort! { |a, b| b.attribute <=> a.attribute }
or
objects_array.sort_by{ |obj| obj.attribute }.reverse
Solution 4 - Ruby
in case you need sorting by two attributes, where first one is more important then second (means taking in account second arguments only if first arguments are equal), then you may do like this
myarray.sort{ |a,b| (a.attr1 == b.attr1) ? a.attr2 <=> b.attr2 : a.attr1 <=> b.attr1 }
or in case of array of arrays
myarray.sort{ |a,b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] }
Solution 5 - Ruby
You can make any class sortable by overriding the <=> method:
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
Now an array of Person objects will be sortable on 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" ]
Solution 6 - Ruby
More elegant objects.sort_by(&:attribute)
, you can add on a .reverse
if you need to switch the order.
Solution 7 - Ruby
Array#sort works well, as posted above:
myarray.sort! { |a, b| a.attribute <=> b.attribute }
BUT, you need to make sure that the <=>
operator is implemented for that attribute. If it's a Ruby native data type, this isn't a problem. Otherwise, write you own implementation that returns -1 if a < b, 0 if they are equal, and 1 if a > b.
Solution 8 - Ruby
Solution 9 - Ruby
@model_name.sort! { |a,b| a.attribute <=> b.attribute }