```Dave Thomas <Dave / PragmaticProgrammer.com> wrote:
>"Wilka" <jvyxn / evghnyvfgvp.pbz> writes:
>
[...]
>Here are a couple of ways. The second may or may not be more
>efficient, as it only does the pattern match and to_i once for each
>string in the array.
>
>      strings = [ "Name 300", "Name 1", "Name 10", "Name 2" ]
>
>      # an inefficient way (if there are large numbers of strings)
>
>      digits = /\d+\$/
>
>      res = strings.sort { |a, b|  digits.match(a)[0].to_i <=>
>digits.match(b)[0].to_i}
>
>      # a more efficient way (perhaps)
>
>      res = strings.
>          collect {|e|    [ digits.match(e)[0].to_i, e ] }.
>          sort    {|a, b| a[0] <=> b[0] }.
>          collect {|e|    e[1]}
>
Note that both of these just sort the strings
based on the embedded number.  The Schwartzian
sort example that I gave earlier pays attention
to the number and works for a larger variety of
strings, including (for instance) mixed text,
most version number schemes, and dotted quad IP
numbers correctly.

(OTOH if I was in a hurry and hadn't already
probably done something like the above as well.)

BTW I made it somewhat more complex (so it will
handle negative numbers, takes into account most
people's preference for case-insensitive sorts,
etc):

def sort_split (s)
# Each piece case insensitive then by number,
# finally usual lexical order
pieces = s.scan(/(\D*)(\d*)/)
pieces.each {|elem|
elem[0].downcase!
elem[1] = elem[1].sub(/^0*/, '').to_i
if "" != elem[0] and "-" == elem[0].slice(-1, 1)
elem[0].chop!
elem[1] *= -1
end
}
pieces.push s
end

things = (-5..20).to_a.map {|i| "thing #{i}"}
things.push (
"thing ", "hello", "world", "This", "That", "This -", "this"
)
puts things.map {|e| sort_split(e)} .sort.map {|e| e[-1]}

Cheers,
Ben
_________________________________________________________________