Create a Array#sort_with_nils method.
If you need this more than once or twice, it could be useful to add an initializer and add a #sort_with_nils method to Array. Something like this:
config/initializers/array.rb
def sort_with_nils( nils_first: true )
nils = [ nil ] * ( self.tally[ nil ] || 0 ) # Counts the number of `nil` values and create an Array of that number of `nil` values. We will add this to the beginning or the end of the Array after sorting.
if nils_first
nils + ( self - [ nil ] ).sort
else
( self - [ nil ] ).sort + nils
end
end
An example:
myarray = [ 1, 2, nil, 4, nil ]
#=> [1, 2, nil, 4, nil]
myarray.sort_with_nils
#=> [nil, nil, 1, 2, 4]
myarray
#=> [1, 2, nil, 4, nil]
myarray.sort_with_nils( nils_first: false )
#=> [1, 2, 4, nil, nil]
myarray
#=> [1, 2, nil, 4, nil]
What I like about this is that:
It doesn't matter if your Array contains Strings or Integers or anything else so you don't need to use arbitrary values to assign to nil to sort them last or first.
It uses the standard .sort method so nothing is overwritten and leverages the power already there.
You can sort nil values first (default) or last (by passing nils_first: false param).
It retains the number of nil values, if that's important, and then you can use .uniq to reduce it to a single nil value if you like.
The operation is not in-place and so it doesn't affect the original Array object.
my_array.compactand thensortit as normal.nil? What is the criteria for sorting?compact,sortand then put thenils back in:s = my_array.compact.sort,s = s + (my_array-s) #=> ["12", "12 months", "13 months", nil, nil]. (The second statement could instead bes = s + [nil]*(my_array.size-s.size).