Reputation: 307
I have an array containing integer values and string type characters as such _
Here is my array array = ["_", 2, 3, "_"]
how can I sort them such that it returns like the following: [2, 3, "_", "_"]
I have tried to sort it with the ruby .sort()
method but it appears as if sort()
does not compare integers with strings and therfore returns an error.
is there a ruby method I am not aware of? Any help or guidance is highly appreciated.
Upvotes: 1
Views: 125
Reputation: 103864
The problem is you can't compare a string to an integer:
> 2<"2"
(irb):15:in `<': comparison of Integer with String failed (ArgumentError)
The fix (with your specific example) is to make array
act as if it is all strings.
Given:
array = ["_", 2, 3, "_"]
If you just want the result to be a uniform string array:
> array.map{|e| e.to_s}.sort
=> ["2", "3", "_", "_"]
If you want the elements to maintain their type:
> array.map{|e| [e.to_s, e]}.sort.map{|e| e[1]}
=> [2, 3, "_", "_"]
Or, alternatively:
> array.sort_by{|e| e.to_s}
=> [2, 3, "_", "_"]
The potential issue here is that if you rely solely on a conversion to a string (which solved the example you gave) you will get a bad result with integers:
> array = ["10", 12, 3, "0", "b", "a"]
=> ["10", 12, 3, "0", "b", "a"]
> array.sort_by{|e| e.to_s}
=> ["0", "10", 12, 3, "a", "b"] # desirable?
Which is not entirely solvable by using .to_i
:
> array.sort_by{|e| e.to_i}
=> ["0", "b", "a", 3, "10", 12] # fixed?
Which maybe is best solved by sorting on both:
> array.sort_by{|e| [e.to_i, e.to_s]}
=> ["0", "a", "b", 3, "10", 12]
Luckily Ruby makes it super easy to choose.
Note, .sort_by
or the other enumerable sorts are not a stable sort so elements that compare equal are potentially returned in different order than given:
> array=[1,2,3,4,5,6,7,8,9]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
> array.sort_by{|e| 0} # make them all compare equal
=> [9, 2, 3, 4, 5, 6, 7, 8, 1]
To fix that now, add an index:
> array.each_with_index.sort_by{|e,i| [0,i]}.map(&:first)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Or, as pointed out in comments:
> array.sort_by.with_index { |e, i| [0, i] }
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Upvotes: 3