Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method to sort strings in descending order (in complex keys)

In order to descend-sort an array a of strings, reverse can be used.

a.sort.reverse

But when you want to use a string among multiple sort keys, that cannot be done. Suppose items is an array of items that have attributes attr1 (String), attr2 (String), attr3 (Integer). Sort can be done like:

items.sort_by{|item| [item.attr1, item.attr2, item.attr3]}

Switching from ascending to descending can be done independently for Integer by multiplying it with -1:

items.sort_by{|item| [item.attr1, item.attr2, -item.attr3]}

But such method is not straightforward for String. Can such method be defined? When you want to do descending sort with respect to attr2, it should be written like:

items.sort_by{|item| [item.attr1, item.attr2.some_method, item.attr3]}
like image 301
sawa Avatar asked Mar 14 '23 01:03

sawa


1 Answers

I think you can always convert your strings into an array of integers (ord). Like this:

strings = [["Hello", "world"], ["Hello", "kitty"], ["Hello", "darling"]]
strings.sort_by do |s1, s2|
  [
    s1,
    s2.chars.map(&:ord).map{ |n| -n }
  ]
end

PS:

As @CarySwoveland caught here is a corner case with empty string, which could be solved with this non elegant solution:

strings.sort_by do |s1, s2|
  [
    s1,
    s2.chars.
       map(&:ord).
       tap{|chars| chars << -Float::INFINITY if chars.empty? }.
       map{ |n| -n }
  ]
end

And @Jordan kindly mentioned that sort_by uses Schwartzian Transform so you don't need preprocessing at all.

like image 200
fl00r Avatar answered Apr 30 '23 13:04

fl00r