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!

···

--
Posted via http://www.ruby-forum.com/.

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".

···

--
Posted via http://www.ruby-forum.com/.

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 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]

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

···

--
Posted via http://www.ruby-forum.com/\.

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[1].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[0] + f.char_numb.to_s
  b.push(tmp_item)

end

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

···

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:

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

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

from:

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

···

On Mar 27, 2012, at 09:45 , Ryan Davis wrote:

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", ...]

Robert Klemme 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.

···

--
Posted via http://www.ruby-forum.com/\.

Jan E. wrote in post #1053507:

Robert Klemme 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

···

--
Posted via http://www.ruby-forum.com/\.