# tricky sort for happy visitors of Paris

Discussion in 'Ruby' started by Josselin, Dec 20, 2006.

1. ### JosselinGuest

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... ;-))

joss

Josselin, Dec 20, 2006

2. ### Guest

Hi --

On Thu, 21 Dec 2006, 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' ]
>
> 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... ;-))

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

--
Q. What's a good holiday present for the serious Rails developer?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
aka The Ruby book for Rails developers!
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Dec 20, 2006

3. ### Rob BiedenharnGuest

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... ;-))
>
>
> 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 Biedenharn http://agileconsultingllc.com

Rob Biedenharn, Dec 20, 2006
4. ### Nicolas DesprèsGuest

On 12/20/06, 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' ]
>
> 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' ]
>

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 =3D /\s(\d+)\$/
re.match(a)
ai =3D \$1.to_i
re.match(b)
bi =3D \$1.to_i
ai <=3D> bi
end

Cheers

--=20
Nicolas Despr=E8s

Nicolas Desprès, Dec 20, 2006
5. ### Farrel LifsonGuest

On 20/12/06, 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' ]
>
> 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... ;-))
>
>
> joss
>
>
>

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

Farrel

Farrel Lifson, Dec 20, 2006
6. ### Jamey CribbsGuest

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

arrondissement_arr.sort_by { |a| a.split.last.to_i }

Jamey

Confidentiality Notice: This email message, including any attachments, is for the sole use of the intended recipient(s) and may contain confidential and/or privileged information. If you are not the intended recipient(s), you are hereby notified that any dissemination, unauthorized review, use, disclosure or distribution of this email and any materials contained in any attachments is prohibited. If you receive this message in error, or are not the intended recipient(s), please immediately notify the sender by email and destroy all copies of the original message, including attachments.

Jamey Cribbs, Dec 20, 2006
7. ### Uma GellerGuest

> 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 Geller
http://umageller.wordpress.com

Uma Geller, Dec 20, 2006
8. ### Peter HickmanGuest

This is just begging for a natural sort order method for the array
class. Has anyone created one yet?

Peter Hickman, Dec 20, 2006
9. ### Uma GellerGuest

> arrondissement_arr.sort_by { |a| a.split.last.to_i }

your arys are better than myne !

thanks for the tip

---
Uma Geller
http://umageller.wordpress.com

Uma Geller, Dec 20, 2006
10. ### Guest

On 12/20/06, Josselin <> wrote:
[...]
>
> ['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... ;-))
>

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

, Dec 20, 2006
11. ### JosselinGuest

On 2006-12-20 16:03:28 +0100, Josselin <> said:

> 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... ;-))
>
>
> 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....

Josselin, Dec 20, 2006
12. ### Devin MullinsGuest

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

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

Devin

Devin Mullins, Dec 20, 2006
13. ### Jos BackusGuest

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:~%

--
Jos Backus
jos at catnook.com

Jos Backus, Dec 20, 2006
14. ### William JamesGuest

Jos Backus wrote:
> 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:~%
>
> --
> Jos Backus
> 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] } }

William James, Dec 20, 2006
15. ### Guest

Hi --

On Thu, 21 Dec 2006, William James wrote:

> Jos Backus wrote:
>> 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:~%
>>
>> --
>> Jos Backus
>> 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] } }

Or:

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

David

--
Q. What's a good holiday present for the serious Rails developer?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
aka The Ruby book for Rails developers!
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Dec 21, 2006
16. ### Jos BackusGuest

On Thu, Dec 21, 2006 at 08:05:06AM +0900, William James wrote:
> Jos Backus wrote:
> > 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:~%
> >
> > --
> > Jos Backus
> > 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] } }

Oops, you're right, I missed that. Clever use of inject, by the way.

--
Jos Backus
jos at catnook.com

Jos Backus, Dec 21, 2006
17. ### Père NoëlGuest

Josselin <> 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 ;-)
--
Père Noël

Père Noël, Dec 21, 2006
18. ### Guest

On 12/20/06, Devin Mullins <> wrote:
>
> 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).

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

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

, Dec 21, 2006