Ruby - Spaceship operator will not work in block for .sort

I am getting an error when I try to use a non-alpha numeric spaceship operator in a sort function.

word = "out-classed"
letters = word.downcase.split('')
letters.sort! do |x, y|
  if y < 'a'
    next
  else
   value = x <=> y
  end
end

      

I get ArgumentError: comparison of String with String failed

, and I'm pretty sure this is happening with the spacecraft operator and not with <comparison.

The interesting part is that when I do the same comparison in irb outside the context of the collation, the comparison works. It also works when the word variable is only letters.

Can someone help me understand why this doesn't only work in this particular context?

+3


source to share


3 answers


Instead, next

you need to return 0, 1, or -1. Try the following:



word = "out-classed"
letters = word.downcase.split('')
letters.sort! do |x, y|
  if y < 'a'
    0
  else
   value = x <=> y
  end
end

      

+2


source


If you try to sort the collection, it x<=>y

should return 0, 1, or -1 for each pair of items in the collection. If <=>

defined artificially for some pairs (for example, 'a'<=>'-' #=> 0

and '-'<=>'a' #=> 0

), your type may return erroneous results.

This is because sorting algorithms do not necessarily evaluate all pairs of items in a collection. If, for example, he finds that:

'a' <=> 'b' #=> 0

      

and

'b' <=> 'c' #=> 0

      

he will conclude that:

`a` <=> `c` #=> 0

      

because sorting the collection must satisfy the transitivity: x <== z

if x <= y

and y <= z

.

For example, if the collection is an array ['z', '-', 'a']

and it detects that 'z' <= '-'

and '-' <= 'a'

, it concludes that 'z' <= 'a'

(and does not evaluate 'z' <=> 'a'

).



That's why:

['z', '-', 'a'].sort { |x,y| p [x,y]; (y < 'a') ? 0 : x<=>y }
  #-> ["z", "-"]
  #-> ["-", "a"]
  #=> ["z", "-", "a"]

      

does not work. You have two options:

Remove items before sorting:

['z', '-', 'a'].select { |c| ('a'..'z').cover?(c) }.
                sort { |x,y| (y < 'a') ? 0 : x<=>y }
  #=> ["a", "z"]

      

or sort all elements of the collection:

['z', '-', 'a'].sort
  #=> ["-", "a", "z"] 

      

If the collection contains non-comparable elements (for example [1,2,'cat']

), you only have to remove the elements from the array until all other elements are comparable.

+3


source


Your problem is here.

if y < 'a'
  next
else
  ...

      

sort

expects you to return a comparison value between each pair , so when you call next

without returning anything, it says the comparison failed.

Try for example. this is:

if y < 'a'
  1
else
  value = x <=> y
end

      

+1


source







All Articles