Crystal: "sort_by" does not work with mixed arrays

Created on 29 Aug 2019  路  3Comments  路  Source: crystal-lang/crystal

"sort_by" does not work with mixed arrays (number and strings) using Crystal 0.30.1 [5e6a1b672] (2019-08-12)

Examples:

### Works
test = [ [0, 1.23], [1, 1.10], [2, 1.15] ]
puts test.sort_by { |x| x[1] }

### Fails
test = [ ["a", 1.23], ["b", 1.10], ["c", 1.15] ]
puts test.sort_by { |x| x[1] }

### ERROR MESSAGE:
In /usr/share/crystal/src/number.cr:176:10
176 | self > other ? 1 : (self < other ? -1 : 0)
^
Error: no overload matches 'Float64#>' with type (Float64 | String)
Overloads are:

  • Float64#>(other : Int8)
  • Float64#>(other : Int16)
  • Float64#>(other : Int32)
  • Float64#>(other : Int64)
  • Float64#>(other : Int128)
  • Float64#>(other : UInt8)
  • Float64#>(other : UInt16)
  • Float64#>(other : UInt32)
  • Float64#>(other : UInt64)
  • Float64#>(other : UInt128)
  • Float64#>(other : Float32)
  • Float64#>(other : Float64)
  • Comparable(T)#>(other : T)
    Couldn't find overloads for these types:
  • Float64#>(other : String)

All 3 comments

Mixed arrays type is the union of the elements types, that is the reason it cant find a method to
compare with a string. In the first case it works because Floats and Integers can be compared.
You should cast it.

test = [ ["a", 1.23], ["b", 1.10], ["c", 1.15] ]
puts test.sort_by { |x| x[1].as(Float64) }

Even better than casting it is to make so that it isn't needed in the first place. If you want typing that is aware of positions like that, use Tuples instead of arrays, or a specialized class.

An example of the Tuple advice:

test = [{"a", 1.23}, {"b", 1.10}, {"c", 1.15}]
puts test.sort_by { |x| x[1] }
Was this page helpful?
0 / 5 - 0 ratings