In Ruby the default sort puts empty strings first.
['', 'g', 'z', 'a', 'r', 'u', '', 'n'].sort
Gives:
["", "", "a", "g", "n", "r", "u", "z"]
However, it's quite common to want empty strings at the end instead.
Doing something like:
['', 'g', 'z', 'a', 'r', 'u', '', 'n'].sort { |a, b| a[0] && b[0] ? a <=> b : a[0] ? -1 : b[0] ? 1 : 0 }
works and gives:
["a", "g", "n", "r", "u", "z", "", ""]
However, this isn't very readable and is not very flexible.
Is there a reasonable and clean way to get sort
in Ruby to put empty strings last? Would it be better to just map to an array with no empty strings, sort, and then pad on the empty strings at the end? Are there other approaches?
arr = ["g", "u", "", "a", "", "r", "n", "z"]
arr.sort_by { |s| [s.empty? ? 1 : 0, s] }
#=> ["a", "g", "n", "r", "u", "z", "", ""]
or
arr.sort_by { |s| s.empty? ? 255.chr : s }
# => ["a", "g", "n", "r", "u", "z", "", ""]
or
empty, non_empty = arr.partition(&:empty?)
#=> [["", ""], ["g", "u", "a", "r", "n", "z"]]
non_empty.sort.concat empty
#=> ["a", "g", "n", "r", "u", "z", "", ""]
The simplest solution I can think of is
a = ['', 'g', 'z', 'a', 'r', 'u', '', 'n']
a.sort.rotate(a.count(''))
#=> ["a", "g", "n", "r", "u", "z", "", ""]
Array#rotate
: Returns a new array by rotating self so that the element at count is the first element of the new array.
So we just rotate by the count of empty strings (""
)
Just count the number of blanks and then use #rotate
to move them to the end:
sorted = ['', 'g', 'z', 'a', 'r', 'u', '', 'n'].sort
blank_count = sorted.count &:empty?
sorted.rotate! blank_count
Here's another variation, defining a custom sort
comparison:
arr = ["g", "u", "", "a", "", "r", "n", "z"]
arr.sort { |s1, s2| (s1.empty? || s2.empty?) ? (s2 <=> s1) : (s1 <=> s2) }
#=> ["a", "g", "n", "r", "u", "z", "", ""]
Using s2 <=> s1
is essentially a "reverse sort" - so in cases where an empty string is being compared against, this orders it at the end of the result rather than the beginning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With