简体   繁体   中英

Ruby sorting even and odd numbers issue

I'm learning Ruby and just started with the sorting. Trying to sort the array like this: [1,3,5,2,4,6] and I'm don't really understand what is wrong with the code. Any help would be appreciated!

[1,2,3,4,5,6].sort do |x,y|
  if x.odd? and y.odd?
    0
  elsif x.odd?
    -1
  else
     1
end  
  if (x.odd? && y.odd?) or (x.even? && y.even?)
  x <=> y
end 
end

First off, let's fix your indentation (and convert to standard Ruby community coding style), so that we can better see what's going on:

[1, 2, 3, 4, 5, 6].sort do |x, y|
  if x.odd? && y.odd?
    0
  elsif x.odd?
    -1
  else
     1
  end

  if (x.odd? && y.odd?) || (x.even? && y.even?)
    x <=> y
  end 
end

Now, the problem becomes obvious: your first conditional expression evaluates to 0 , -1 , or 1 , but nothing is being done with this value . The value is not stored in a variable, not passed as an argument, not returned. It is simply ignored. The entire expression is a NO-OP.

Which means that the only thing that matters is this:

  if (x.odd? && y.odd?) || (x.even? && y.even?)
    x <=> y
  end 

This will return 0 for two elements that are equal, -1 or 1 for two elements that are unequal but both odd or both even, and nil (which to sort means "these two elements are un-comparable, they don't have a defined relative ordering") for elements where one element is odd and one is even. Since sort requires all elements to be comparable, it will then abort.

The easiest way to approach this problem would probably be to partition the array into odds and evens, sort them separately, and then concatenate them:

[1, 2, 3, 4, 5, 6].partition(&:odd?).map(&:sort).inject(:concat)
#=> [1, 3, 5, 2, 4, 6]

Or do it the other way round, just sort them all, and then partition ( Thanks @Eric Duminil ):

[1, 2, 3, 4, 5, 6].sort.partition(&:odd?).inject(:concat)
#=> [1, 3, 5, 2, 4, 6]

It's probably the first time I ever used a negative modulo :

  • i % -2 is -1 if i is odd
  • i % -2 is 0 if i is even

So sorting by i % -2 first and then by i should achieve the desired result.

If you want even numbers before odd numbers, you can sort by i % 2 .


[3, 2, 1, 5, 6, 4].sort_by{ |i| [ i % -2, i] }
#=> [1, 3, 5, 2, 4, 6]

Thanks to @Stefan for his original idea!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM