Reputation: 1902
I have a SizeMatters
class that creates an object from a given string. In order to sort these objects in an array, I've implemented the <=>(other)
method. But the following code only helps the objects to be sorted by size. I also want the array to be sorted alphabetically.
class SizeMatters
include Comparable
attr :str
def <=>(other)
str.size <=> other.str.size
end
def initialize(str)
@str = str
end
def inspect
@str
end
end
s1 = SizeMatters.new("Z")
s2 = SizeMatters.new("YY")
s3 = SizeMatters.new("xXX")
s4 = SizeMatters.new("aaa")
s5 = SizeMatters.new("bbb")
s6 = SizeMatters.new("WWWW")
s7 = SizeMatters.new("VVVVV")
[ s3, s2, s5, s4, s1 , s6, s7].sort #[Z, YY, bbb, xXX, aaa, WWWW, VVVVV]
What I want is this
[ s3, s2, s5, s4, s1 , s6, s7].sort #[Z, YY, aaa, bbb, xXX, WWWW, VVVVV]
How can I write <=>(other)
so that objects in array can be sorted first by size and then alphabetically?
Upvotes: 1
Views: 679
Reputation: 110725
You said you want to sort the strings by size and break ties by sortings strings of the same length by lexicographical ("dictionary") order. Yes, you will need to define SizeMatters#<=>
, but it may be a mistake to define it for sorting, as that would prevent you from comparing stings in the normal way elsewhere in your class. Consider keeping your definition of <=>
and use Enumerable#sort_by for the sorting.
class SizeMatters
include Comparable
attr_reader :str
def initialize(str)
@str = str
end
def <=>(other)
str.size <=> other.str.size
end
def sort_criteria
[str.size, str]
end
def lexi_precede?(other)
str < other.str
end
end
[s3, s2, s5, s4, s1 , s6, s7].sort_by(&:sort_criteria).map(&:str)
#=> ["Z", "YY", "aaa", "bbb", "xXX", "WWWW", "VVVVV"]
s1.lexi_precede?(s2)
#=> false
Upvotes: 1
Reputation: 80075
Define <=>
like this:
def <=>(other)
[str.size, str] <=> [other.str.size, other.str]
end
Upvotes: 6