Ruby String::negative
I had an interesting scenario in a project recently: I had to sort an array of objects in alphabetic order of one field but reverse alphabetic order of another.
Sorting an array in ascending order of one numerical field and descending order of another is simple enough:
array.sort_by{|x| [x.numeric_1, x.numeric_2 * -1]}
But there is no way to multiply a string by -1.
Until now!
class String
def negative
self.chars.map{|x|
x.ord > 96 ?
(90 - (x.ord - 97)).chr :
(122 - (x.ord - 65)).chr }.join
end
end
Basically, this creates a number line with 0 being between Z
and a
.
Because Z
is 1 away from the “0”, it corresponds to -1
. Similarly, a
is one away from “0” in the other direction, therefore it corresponds to 1
. This makes a
the negative
of Z
. Similarly, z
becomes the negative
of A
.
Example
Person = Struct.new(:f_name, :l_name)
entries = [
Person.new("Kana", "Delle"),
Person.new("Ana", "Belle"),
Person.new("Zana", "Celle"),
Person.new("Ana", "Zelle"),
]
puts entries.sort_by{|x| [x.f_name, x.l_name.negative]}
#<struct Person f_name="Ana", l_name="Zelle">
#<struct Person f_name="Ana", l_name="Belle">
#<struct Person f_name="Kana", l_name="Delle">
#<struct Person f_name="Zana", l_name="Celle">
Caveats:
- I didn’t check the performance impact
- I specifically only cared about
[A..z]