I was researching how to fiddle with special sorting mechanisms in Ruby. I ended up rewriting this neat JavaScript solution in Ruby:
class SpecialStr
include Comparable
attr_accessor :str
def initialize (str)
@str = str
end
def <=> (other)
self_num, self_string = @str.split(' ')
other_num, other_string = other.str.split(' ')
self_num > other_num ? 1 : other_num > self_num ? -1 :
self_string > other_string ? -1 : 1
end
end
arr = ['2 xxx', '20 axxx', '2 m', '38 xxxx', '20 bx', '8540 xxxxxx', '2 z']
arr_object = []
arr.each { |str| arr_object << SpecialStr.new(str) }
arr_object.sort! { |x, y| y <=> x }
output_arr = []
arr_object.each { |obj| output_arr << obj.str}
puts output_arr
This has the desired output (numbers descending, then strings ascending):
8540 xxxxxx
38 xxxx
20 axxx
20 bx
2 m
2 xxx
2 z
But the code seemed unnecessarily complicated. (Ruby's supposed to be more concise than JS!) So I asked myself (and now I ask you), why can't I just do this?
def <=> (other)
self_num, self_string = self.split(' ')
other_num, other_string = other.split(' ')
self_num > other_num ? 1 : other_num > self_num ? -1 :
self_string > other_string ? -1 : 1
end
arr = ['2 xxx', '20 axxx', '2 m', '38 xxxx', '20 bx', '8540 xxxxxx', '2 z']
arr.sort! { |x, y| y <=> x }
puts arr
This outputs incorrectly, based on sort
as if I had not redefined <=>
:
8540 xxxxxx
38 xxxx
20 bx
20 axxx
2 z
2 xxx
2 m
The code here is shorter, but doesn't work. It uses the version of <=>
built into Ruby's Comparable
module, rather than my attempt to override it. Why wasn't I able to override it? Can methods be overridden only inside of classes or modules? Is there a shorter way to write that first script in Ruby? (Sorry if this is a noob question, I'm a beginner.)