Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 296
Appunu Avatar asked Apr 22 '15 20:04

Appunu


People also ask

How do you sort an array of strings in Ruby?

In Ruby, it is easy to sort an array with the sort() function. When called on an array, the sort() function returns a new array that is the sorted version of the original one.

How do you sort a case insensitive in Ruby?

The question becomes: how can you sort an array in reverse order, or sort strings in a case-insensitive manner? Ruby lets you do this by specifying how comparison ought to be done. You put this in a do / end block after the word sort . The following code will sort an array in descending order.

How to sort data in Ruby?

The Ruby sort method works by comparing elements of a collection using their <=> operator (more about that in a second), using the quicksort algorithm. You can also pass it an optional block if you want to do some custom sorting. The block receives two parameters for you to specify how they should be compared.

Can you sort elements in a Ruby hash object?

You can use the sort method on an array, hash, or another Enumerable object & you'll get the default sorting behavior (sort based on <=> operator) You can use sort with a block, and two block arguments, to define how one object is different than another (block should return 1, 0, or -1)


2 Answers

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"
like image 28
Cary Swoveland Avatar answered Sep 28 '22 15:09

Cary Swoveland


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

like image 145
hirolau Avatar answered Sep 28 '22 16:09

hirolau