# Sort array of strings with integers

i have this array

b=[a1 a3 a2 a4 a7 a6 a5 a8 a9 a10]

why is it when I perform b.sort!
the result is:
b=[a1 a10 a2 a3 a4 a5 a6 a7 a8 a9]

how can i make it
b=[a1 a2 a3 a4 a5 a6 a7 a8 a9 a10]

thanks!

Hi,

I assume you mean

b = %w[a1 a3 a2 a4 a7 a6 a5 a8 a9 a10]

Because what you wrote down isn’t valid Ruby code.

Strings are ordered lexicographically by default. That is, the
characters are compared one by one. This makes the string “a10” smaller
than “a2”, because the character “1” is smaller than “2” (the rest of
the string is ignored).

If you want to change this behavious, you have to provide your own
sorting rule:

b.sort_by! {|s| s[/\d+/].to_i}

Each element is passed to the block and then the block values are
compared. In this case, the elements are compared by the “indices”.

Jan E. wrote in post #1053502:

I assume you mean

b = %w[a1 a3 a2 a4 a7 a6 a5 a8 a9 a10]

Because what you wrote down isn’t valid Ruby code.

The code is syntactically valid. And if all a1, a2 etc. are local
variables or methods then this code will even execute properly.

Kind regards

robert

Robert K. wrote in post #1053503:

The code is syntactically valid. And if all a1, a2 etc. are local
variables or methods then this code will even execute properly.

There are no commas, which doesn’t work for normal array literals. Also
the question wouldn’t make sense if a1, a2, … were local variables or
methods.

On Mar 27, 2012, at 4:04 AM, Jan E. wrote:

Strings are ordered lexicographically by default. That is, the
characters are compared one by one. This makes the string “a10” smaller
than “a2”, because the character “1” is smaller than “2” (the rest of
the string is ignored).

If you want to change this behavious, you have to provide your own
sorting rule:

I found for some types of large sorts, I have better luck breaking
things up, It also gives me the flexibility to do multiple types of
sorts on the same data (I have one script for sorting chip ball maps
where we need to do alpha sorts and then pin number sorts, so I use a
routine similar to this:

class Map <
Struct.new(:char_alpha, :char_numb)
end

b = %w[a1 a3 a2 a4 a7 a6 a5 a8 a9 a10]

storage = Array.new

b.each do |item|

a_char = Map.new

item_alpha = item.split(/\d/)
a_char.char_alpha = item_alpha

item_number = item.split(/\D/)
a_char.char_numb = item_number.to_i # convert to integer for sort

storage.push(a_char)

end
b.clear # remove contents of old array

storage.sort_by! { |a| [a.char_alpha, a.char_numb]} # sorting order
performed here first by alpha then numeric

storage.each do |f| # build new array for b sorted correctly

tmp_item = f.char_alpha + f.char_numb.to_s
b.push(tmp_item)

end

puts b # to display results only, not really needed.

=-=-=-=-=-=-=-

ruby-1.9.3-p125 :020 > puts b
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
=> nil

-=-=-=-=-=-=-=-=-

The cool thing is you can now do all kinds of multi sorts using this
type of arrangement. Comes in handy where you have to sort multiple
arrays and then merge those results at the end.

Wayne

Jan E. wrote in post #1053507:

Robert K. wrote in post #1053503:

The code is syntactically valid. And if all a1, a2 etc. are local
variables or methods then this code will even execute properly.

There are no commas, which doesn’t work for normal array literals. Also
the question wouldn’t make sense if a1, a2, … were local variables or
methods.

You got me. Right you are. Sorry for the noise.

Cheers

robert

On Mar 27, 2012, at 00:59 , Ri Houjun wrote:

i have this array

b=[a1 a3 a2 a4 a7 a6 a5 a8 a9 a10]

why is it when I perform b.sort!
the result is:
b=[a1 a10 a2 a3 a4 a5 a6 a7 a8 a9]

how can i make it
b=[a1 a2 a3 a4 a5 a6 a7 a8 a9 a10]

p Dir[“f*.txt”].sort

# => [“f0.txt”, “f1.txt”, “f10.txt”, “f11.txt”, …, “f2.txt”, “f3.txt”,

…]

class Array
def human_sort
sort_by { |item| item.to_s.split(/(\d+)/).map { |e| [e.to_i, e] } }
end
end

p Dir[“f*.txt”].human_sort

# => [“f0.txt”, “f1.txt”, “f2.txt”, “f3.txt”, “f4.txt”, “f5.txt”,

“f6.txt”, …]

On Mar 27, 2012, at 09:45 , Ryan D. wrote:

end

p Dir[“f*.txt”].human_sort

# => [“f0.txt”, “f1.txt”, “f2.txt”, “f3.txt”, “f4.txt”, “f5.txt”, “f6.txt”, …]

from:

http://blog.zenspider.com/blog/2012/01/array-natural_sort.html