Reputation: 1654
how to sort array if i have array like this in ruby?
example :
my_array = ["12 months", "13 months", nil, nil, "12"]
i want get result like this :
my_array = ["12", "12 months", "13 months", nil, nil]
when i try :
my_array.sort{|x, y| x <=> y}
i get error like this :
ArgumentError Exception: comparison of String with nil failed
how to fix it?
thanks before
Upvotes: 2
Views: 812
Reputation: 47481
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.
Upvotes: 0
Reputation: 1051
You can compare a 2 dimensions array: whether string is nil & the string itself.
my_array = ["12 months", "13 months", nil, nil, "12"]
my_array.sort_by { |x| [x ? 0 : 1, x] }
=> ["12", "12 months", "13 months", nil, nil]
Upvotes: 0
Reputation: 66837
Here's a nice short way to do it, but it will only work if you can come up with a string that's guaranteed to be "greater than" all the strings in the array (which was easy here):
my_array.sort_by { |x| x || "Z" }
=> ["12", "12 months", "13 months", nil, nil]
Upvotes: 2
Reputation: 23939
Handle the nil, this will get you close...
2.1.2 :010 > my_array.sort { |x,y| x && y ? (x <=> y) : (x ? -1 : 1) }
=> ["12", "12 months", "13 months", nil, nil]
It's not exact, '12'
comes before the rest based on the <=>
comparison. If you want more control you'll need to have a more complex comparison block.
Upvotes: 3