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

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)

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 Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

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

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 12/20/06, Josselin <josselin@wanadoo.fr> 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' ]

--
Nicolas Desprès

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

Farrel

···

On 20/12/06, Josselin <josselin@wanadoo.fr> 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... ;-))

thanks for your light

joss

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.

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

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

[...]

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

···

On 12/20/06, Josselin <josselin@wanadoo.fr> wrote:

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

···

On 2006-12-20 16:03:28 +0100, Josselin <josselin@wanadoo.fr> 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... ;-))

thanks for your light

joss

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

···

--
Duane Johnson
(canadaduane)

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

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

your arys are better than myne ! :slight_smile:

thanks for the tip

···

---
Uma Geller

johan556@gmail.com 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

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 12/20/06, Jos Backus <jos@catnook.com> 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"]

--
Duane Johnson
(canadaduane)

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

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:

···

Josselin <josselin@wanadoo.fr> wrote:

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

--
Père Noël

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)

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

···

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

--
Jos Backus
jos at catnook.com

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

···

On 12/20/06, Devin Mullins <twifkak@comcast.net> wrote:

johan556@gmail.com 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 } }