Appunu
Appunu

Reputation: 83

Ruby custom string sort

Input string:

1654AaBcDddeeFF 

Output string:

1456acddeeABDFF

Code I tried:

test_array = []
'1654AaBcDddeeFF'.each_byte do |char|
  test_array << char
end

test_array.sort.pack('C*')
# => 1456ABDFFacddee

But I would like to see the upper case characters at last.

Upvotes: 5

Views: 1032

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110685

Since @hirolau's already taken swapcase, I offered an alternative (even though I prefer his answer). Alas, @Stefan identified a flaw, but suggested a nice fix:

str = '1654AaBcDddeeFF'

order_array = [*'0'..'9',*'a'..'z',*'A'..'Z']
str.each_char.sort_by { |c| order_array.index(c) }.join
  #=> "1456acdeABDF" 

(I am a mere scribe.)

One advantage of this approach is that you could use it for other orderings. For example, if:

str = '16?54!AaBcDdde,eFF'

and you also wanted to group the characters `'!?,' at the beginning, in that order, you could write:

order_array = [*'!?,'.chars,*'0'..'9',*'a'..'z',*'A'..'Z']
str.each_char.sort_by { |c| order_array.index(c) }.join
  #=> "!?,1456acdeABDF" 

We can make this a bit more efficient by converting order_array to a hash. For the last example:

order_hash = Hash[order_array.each_with_index.to_a]

then:

str.each_char.sort_by { |c| order_hash[c] }.join
  # => "!?,1456acddeeABDFF"

Upvotes: 5

hirolau
hirolau

Reputation: 13901

What about this?

p '1654AaBcDddeeFF'.each_char.sort_by(&:swapcase).join #=> "1456acddeeABDFF"

Edit: As @Cary Swoveland pointed out .chars is just a shortcut for .each_char.to_a and since we do not need to to_a here .each_char is a better method to use

Upvotes: 13

Related Questions