Tricky sort for happy visitors of Paris

all happy visitors of Paris know about the ‘arrondissement’, an
administrative division of the city… 20 divisions

selecting them from a city table I can map them as :

[‘Paris 1’ , ‘Paris 10’ , ‘Paris 11’ , … ‘Paris 19’ , ‘Paris 2’ ,
‘Paris 20’ , ‘Paris 3’ , … ‘Paris 9’ ]

is there any way to sort this array and get :

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ]

which seems betetr in a list… ;-))

thanks for your light

joss

On 12/20/06, Josselin [email protected] wrote:

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ]

Somethings like (I’ve not tested the code):

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ].sort do |a, b|
re = /\s(\d+)$/
re.match(a)
ai = $1.to_i
re.match(b)
bi = $1.to_i
ai <=> bi
end

Cheers

On 20/12/06, Josselin [email protected] wrote:

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ]

which seems betetr in a list… ;-))

thanks for your light

joss

[“Paris 1”,“Paris 10”,“Paris 2”].sort_by{|a| a.split[1].to_i}

Farrel

Hi –

On Thu, 21 Dec 2006, Josselin wrote:

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ , ‘Paris
11’ , … ‘Paris 19’ , ‘Paris 20’ ]

which seems betetr in a list… ;-))

You could do:

arronds.sort_by {|a| a[/\d+/].to_i }

That will grab the digits, convert them to an integer, and sort based
on that.

David

On Dec 20, 2006, at 10:05 AM, Josselin wrote:

all happy visitors of Paris know about the ‘arrondissement’, an
administrative division of the city… 20 divisions

selecting them from a city table I can map them as :

[‘Paris 1’ , ‘Paris 10’ , ‘Paris 11’ , … ‘Paris 19’ , ‘Paris
2’ , ‘Paris 20’ , ‘Paris 3’ , … ‘Paris 9’ ]

paris = (1…20).map {|i| “Paris #{i}”}.sort
=> [“Paris 1”, “Paris 10”, “Paris 11”, “Paris 12”, “Paris 13”, “Paris
14”, “Paris 15”, “Paris 16”, “Paris 17”, “Paris 18”, “Paris 19”,
“Paris 2”, “Paris 20”, “Paris 3”, “Paris 4”, “Paris 5”, “Paris 6”,
“Paris 7”, “Paris 8”, “Paris 9”]

is there any way to sort this array and get :

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ]

which seems betetr in a list… ;-))

thanks for your light

joss

paris.sort_by { |division| division.match(/(\d+)/)[1].to_i }
=> [“Paris 1”, “Paris 2”, “Paris 3”, “Paris 4”, “Paris 5”, “Paris 6”,
“Paris 7”, “Paris 8”, “Paris 9”, “Paris 10”, “Paris 11”, “Paris 12”,
“Paris 13”, “Paris 14”, “Paris 15”, “Paris 16”, “Paris 17”, “Paris
18”, “Paris 19”, “Paris 20”]

if you have other cities or more than one embedded number, this is
likely too simple, but it works for your example.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

which seems betetr in a list… ;-))

arrondissements = [“Paris 1”, “Paris 2”,“Paris 4”, “Paris 3”]
sorted_array = arrondissements.sort_by {|e| e.split(" ")[1].to_i }


Uma G.

On 12/20/06, Josselin [email protected] wrote:
[…]

I have had a similar problem several times (but not with Paris :), and
I wrote a general utility function like this:

def sort_numbers_numerically(arr)
arr.sort_by do |str|
i = 0
str.split(/(\d+)/).map do |part|
i += 1
i % 2 == 0 ? part.to_i : part
end
end
end

It is of course very similar to the previously proposed solutions, but
is more general in that it sorts strings with several numbers in them,
treating each number “numerically” (one extreme example could be
IP-numbers).

/johan

On 2006-12-20 16:03:28 +0100, Josselin [email protected] said:

[‘Paris 1’ , ‘Paris 2’ , ‘Paris 3’ , … ‘Paris 9’ , ‘Paris 10’ ,
‘Paris 11’ , … ‘Paris 19’ , ‘Paris 20’ ]

which seems betetr in a list… ;-))

thanks for your light

joss

Thanks to all of you… cannot invite you for a Xmas drink on the
Champs-Elysees but cheers…
(whatever I am not living in Paris… but in the Celtic land… the
French Far West…

paris = (1…20).map {|i| “Paris #{i}”}.sort

=> [“Paris 1”, “Paris 10”, “Paris 11”, “Paris 12”, “Paris 13”, “Paris
14”,
“Paris 15”, “Paris 16”, “Paris 17”, “Paris 18”, “Paris 19”, “Paris 2”,
“Paris 20”, “Paris 3”, “Paris 4”, “Paris 5”, “Paris 6”, “Paris 7”,
“Paris
8”, “Paris 9”]

paris.sort_by { |a| a.to_s.split.map{ |w| “%05d” % w rescue w } }

=> [“Paris 1”, “Paris 2”, “Paris 3”, “Paris 4”, “Paris 5”, “Paris 6”,
“Paris
7”, “Paris 8”, “Paris 9”, “Paris 10”, “Paris 11”, “Paris 12”, “Paris
13”,
“Paris 14”, “Paris 15”, “Paris 16”, “Paris 17”, “Paris 18”, “Paris 19”,
“Paris 20”]

[1, 2, 3, “One”, “Two”, “Three”, “Paris 1”, “Paris 11”, “Paris 10”,
“Paris
9”, “Rome”, “Rome 1”, “Rome 2”].sort_by { |a| a.to_s.split.map{ |w|
“%05d” %
w rescue w } }

=> [1, 2, 3, “One”, “Paris 1”, “Paris 9”, “Paris 10”, “Paris 11”,
“Rome”,
“Rome 1”, “Rome 2”, “Three”, “Two”]

More generally:

lizzy:~% irb
irb(main):001:0> arrondissements = [“Paris 1”, “Paris 2”,“Paris 4”,
“Paris 3”, “Lyon 2”, “Lyon 1”]
=> [“Paris 1”, “Paris 2”, “Paris 4”, “Paris 3”, “Lyon 2”, “Lyon 1”]
irb(main):002:0> sorted_array = arrondissements.sort_by {|e| [e.split("
")]}
=> [“Lyon 1”, “Lyon 2”, “Paris 1”, “Paris 2”, “Paris 3”, “Paris 4”]
irb(main):003:0> %
lizzy:~%

[email protected] wrote:

It is of course very similar to the previously proposed solutions, but
is more general in that it sorts strings with several numbers in them,
treating each number “numerically” (one extreme example could be
IP-numbers).
What about this?
arr.sort_by {|s| s.scan(/\d+/).map {|n| n.to_i } }

Devin

Jos B. wrote:

Jos B.
jos at catnook.com

Won’t work for

arrondissements = “Paris 1”, “Paris 2”,“Paris 12”, “Paris 3”,
“Lyon 2”, “Lyon 1”

For the 2nd field, you need a numeric comparison.

p arrondissements.sort_by {|e| e.split.inject{|a,b| [a,b.to_i] } }

On 12/20/06, Jos B. [email protected] wrote:

I think that gets us back to the original problem, namely, that numbers
with
an unequal number of digits will be incorrectly sorted using due to
string
comparison:

irb(main)> arrondissements = [“Paris 1”, “Paris 2”,“Paris 4”, “Paris 3”,
“Lyon 2”, “Lyon 1”, “Paris 10”]
irb(main)> arrondissements.sort_by {|e| [e.split(" ")]}
=> [“Lyon 1”, “Lyon 2”, “Paris 1”, “Paris 10”, “Paris 2”, “Paris 3”,
“Paris
4”]

Note the position of “Paris 10”. This is why the zero-padding is
necessary
in my previous example.

On Thu, Dec 21, 2006 at 08:05:06AM +0900, William J. wrote:


p arrondissements.sort_by {|e| e.split.inject{|a,b| [a,b.to_i] } }
Oops, you’re right, I missed that. Clever use of inject, by the way.

Hi –

On Thu, 21 Dec 2006, William J. wrote:


p arrondissements.sort_by {|e| e.split.inject{|a,b| [a,b.to_i] } }
Or:

require ‘scanf’
p @arrondissements.sort_by {|e| e.scanf("%s%d") }

David

Josselin [email protected] wrote:

whatever I am not living in Paris… but in the Celtic land… the
French Far West…

Then, u’re living with an unefficient(*) umbrella over the head ???

  • unefficient because in france “little britany” their is too much wing
    to let you open your umbrella :wink:

On 12/20/06, Devin M. [email protected] wrote:

[email protected] wrote:

It is of course very similar to the previously proposed solutions, but
is more general in that it sorts strings with several numbers in them,
treating each number “numerically” (one extreme example could be
IP-numbers).

What about this?
arr.sort_by {|s| s.scan(/\d+/).map {|n| n.to_i } }

My example with IP-numbers was perhaps an ill-chosen one. I just
wanted to indicate that my solution could handle several numbers in
the string.

It also considers the string parts as significant. Suppose the input
is like this:

arr = [
    "Paris 1", "Paris 5", "Paris 14",
    "Lyon 2",  "Lyon 6",  "Lyon 15",
]

Your code will give:

 ["Paris 1", "Lyon 2", "Paris 5", "Lyon 6", "Paris 14", "Lyon 15"]

and my code gives:

["Lyon 2", "Lyon 6", "Lyon 15", "Paris 1", "Paris 5", "Paris 14"]

I guess the code one would choose depends on exactly what one wants to
accomplish. In the general case it may be important to consider the
string parts too (e.g. “Paris” and “Lyon”) and not just look at the
numbers.

/johan