Reputation: 285
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?
Upvotes: 9
Views: 1510
Reputation: 28305
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.
Upvotes: 1
Reputation: 110685
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", "", ""]
Upvotes: 9
Reputation: 29373
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 (""
)
Upvotes: 4
Reputation: 9407
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
Upvotes: 2