2

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

6
  • 3
    if you don't need nil. then do my_array.compact and then sort it as normal. Commented Jun 18, 2014 at 5:35
  • 2
    Does the array only consist of strings and nil? What is the criteria for sorting? Commented Jun 18, 2014 at 5:37
  • Further to @G.B.'s suggestion, one could compact, sort and then put the nils back in: s = my_array.compact.sort, s = s + (my_array-s) #=> ["12", "12 months", "13 months", nil, nil]. (The second statement could instead be s = s + [nil]*(my_array.size-s.size). Commented Jun 18, 2014 at 7:55
  • What is your comparison logic? It's not at all clear from your question. E.g. Why does "12 months" come before "13 months" but "12" comes after "13 months"? Commented Jun 18, 2014 at 9:40
  • sorry my mistake, i have already edit my questions... thanks @JörgWMittag Commented Jun 18, 2014 at 9:42

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

when using nested ternary operators, use parenthesis for better readability...
2

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]

Comments

0

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]

Comments

0

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:

  1. 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.

  2. It uses the standard .sort method so nothing is overwritten and leverages the power already there.

  3. You can sort nil values first (default) or last (by passing nils_first: false param).

  4. 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.

  5. The operation is not in-place and so it doesn't affect the original Array object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.