# Sort problem

**URL:** <https://rubytalk.org/t/sort-problem/1047>\
**Category:** ruby-talk\
**Created:** [6 August 2002 23:54 UTC](https://rubytalk.org/t/sort-problem/1047 "2002-08-06T23:54:47Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ian\_Macdonald](https://avatars.discourse-cdn.com/v4/letter/i/f19dbf/32.png) [@Ian\_Macdonald](https://rubytalk.org/u/Ian_Macdonald)\
**Post date:** [6 August 2002 23:54 UTC](https://rubytalk.org/t/sort-problem/1047/1 "2002-08-06T23:54:47Z")

</div>

Hi,

I have a file with data like this:

ina1  
ina15  
inb12  
ina9  
inc10  
inda12  
inef14  
inab14  
inzz8  
inzz80  
inzz9

etc.

I want to sort it alphabetically on the first part of the string, then  
numerically on the second part.

The sorted file should look like this:

ina1  
ina9  
ina15  
inab14  
inb12  
inc10  
inda12  
inef14  
inzz8  
inzz9  
inzz80

However, I can’t seem to write the Ruby code to do this properly.

Having written the Perl to do this kind of thing many times before, I  
set about writing it in Perl and sure enough, the Perl version  
works. The Ruby code is so analagous that I just can’t see where I’m  
going wrong.

Here are the two versions:

Perl

> **···**
>
> * * *
> 
> undef $/;  
> @foo = sort { ($c,$d) = ($a =~ /^([a-z]+)([0-9]+)$/);  
> ($e,$f) = ($b =~ /^([a-z]+)([0-9]+)$/);  
> $c cmp $e or $d \<=\> $f} split(/\n/, \<\>);  
> print join “\n”, @foo’
> 
> ## Ruby
> 
> $/ = nil  
> foo = gets.split("\n")  
> r = /^([a-z]+)([0-9]+)$/  
> foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> e,f = r.match(b)[1,2]  
> c \<=\> e or d.to\_i \<=\> f.to\_i}  
> puts foo
> 
> The Ruby version outputs this:
> 
> ina1  
> ina15  
> ina9  
> inab14  
> inb12  
> inc10  
> inda12  
> inef14  
> inzz80  
> inzz8  
> inzz9
> 
> which shows that the numeric comparison on the second part of the  
> string is clearly not working, leading me to suspect that the \<=\>  
> operator doesn’t work with objects of type Fixnum, but according to  
> the docs, it gets mixed in from Comparable.
> 
> So, what’s wrong with the Ruby code? This is Ruby 1.6.7, in case that  
> matters.
> 
> ## Ian
> 
> Ian Macdonald | Somewhere in Tenafly, New Jersey, a  
> [ian@caliban.org](mailto:ian@caliban.org) | chiropractor is viewing “Leave it to  
> \> Beaver”!  
> \>  
> \>

---

<div class="post-metadata">

**Author:** ![David\_Alan\_Black1](https://avatars.discourse-cdn.com/v4/letter/d/278dde/32.png) [@David\_Alan\_Black1](https://rubytalk.org/u/David_Alan_Black1)\
**Post date:** [7 August 2002 00:22 UTC](https://rubytalk.org/t/sort-problem/1047/2 "2002-08-07T00:22:24Z")

</div>

Hello –

> **···**
>
> On Wed, 7 Aug 2002, Ian Macdonald wrote:
> 
> > Hi,
> > 
> > I have a file with data like this:
> > 
> > ina1  
> > ina15  
> > inb12  
> > ina9  
> > inc10  
> > inda12  
> > inef14  
> > inab14  
> > inzz8  
> > inzz80  
> > inzz9
> > 
> > etc.
> > 
> > I want to sort it alphabetically on the first part of the string, then  
> > numerically on the second part.  
> > $/ = nil  
> > foo = gets.split(“\n”)  
> > r = /^([a-z]+)([0-9]+)$/  
> > foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> > e,f = r.match(b)[1,2]  
> > c \<=\> e or d.to\_i \<=\> f.to\_i}  
> > puts foo
> > 
> > [doesn’t work]
> 
> It’s because \<=\> returns -1, 0, or 1, all of which are true in  
> Ruby.
> 
> You could drop in this last line of the sort:
> 
> (c == e) and (d.to\_i \<=\> f.to\_i) or (c \<=\> e)}
> 
> David
> 
> –  
> David Alan Black  
> home: [dblack@candle.superlink.net](mailto:dblack@candle.superlink.net)  
> work: blackdav@shu.edu  
> Web: [http://pirate.shu.edu/~blackdav](http://pirate.shu.edu/~blackdav)

---

<div class="post-metadata">

**Author:** ![Park\_Heesob5](https://avatars.discourse-cdn.com/v4/letter/p/77aa72/32.png) [@Park\_Heesob5](https://rubytalk.org/u/Park_Heesob5)\
**Post date:** [7 August 2002 00:22 UTC](https://rubytalk.org/t/sort-problem/1047/3 "2002-08-07T00:22:54Z")

</div>

Hi,

“Ian Macdonald” [ian@caliban.org](mailto:ian@caliban.org) wrote in message  
[news:20020806235442.GA17078@caliban.org](mailto:news:20020806235442.GA17078@caliban.org)…

> Hi,
> 
> I have a file with data like this:
> 
> ina1  
> ina15  
> inb12  
> ina9  
> inc10  
> inda12  
> inef14  
> inab14  
> inzz8  
> inzz80  
> inzz9
> 
> etc.
> 
> I want to sort it alphabetically on the first part of the string, then  
> numerically on the second part.

…

> ## Ruby
> 
> $/ = nil  
> foo = gets.split(“\n”)  
> r = /^([a-z]+)([0-9]+)$/  
> foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> e,f = r.match(b)[1,2]  
> c \<=\> e or d.to\_i \<=\> f.to\_i}  
> puts foo
> 
> So, what’s wrong with the Ruby code? This is Ruby 1.6.7, in case that  
> matters.

Try this:

$/ = nil  
foo = gets.split(“\n”)  
r = /^([a-z]+)([0-9]+)$/  
foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
e,f = r.match(b)[1,2]  
(c \<=\> e).nonzero? || d.to\_i \<=\> f.to\_i}  
puts foo

> ## Ian
> 
> Ian Macdonald | Somewhere in Tenafly, New Jersey, a  
> [ian@caliban.org](mailto:ian@caliban.org) | chiropractor is viewing “Leave it to  
> \> Beaver”!  
> \>  
> \>

Park Heesob

---

<div class="post-metadata">

**Author:** ![WATANABE\_Hirofumi1](https://avatars.discourse-cdn.com/v4/letter/w/c2a13f/32.png) [@WATANABE\_Hirofumi1](https://rubytalk.org/u/WATANABE_Hirofumi1)\
**Post date:** [7 August 2002 05:31 UTC](https://rubytalk.org/t/sort-problem/1047/4 "2002-08-07T05:31:47Z")

</div>

Hi,

Ian Macdonald [ian@caliban.org](mailto:ian@caliban.org) writes:

:Ruby  
:----  
:  
:$/ = nil  
:foo = gets.split("\n")  
:r = /^([a-z]+)([0-9]+)$/  
:foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
: e,f = r.match(b)[1,2]  
: c \<=\> e or d.to\_i \<=\> f.to\_i}  
:puts foo

How about Array#\<=\> ?

[c, d.to\_i] \<=\> [e, f.to\_i]

> **···**
>
> –  
> eban

---

<div class="post-metadata">

**Author:** ![David\_Alan\_Black1](https://avatars.discourse-cdn.com/v4/letter/d/278dde/32.png) [@David\_Alan\_Black1](https://rubytalk.org/u/David_Alan_Black1)\
**Post date:** [7 August 2002 00:45 UTC](https://rubytalk.org/t/sort-problem/1047/5 "2002-08-07T00:45:25Z")

</div>

Hi –

> **···**
>
> On Wed, 7 Aug 2002, Park Heesob wrote:
> 
> > $/ = nil  
> > foo = gets.split(“\n”)  
> > r = /^([a-z]+)([0-9]+)$/  
> > foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> > e,f = r.match(b)[1,2]  
> > (c \<=\> e).nonzero? || d.to\_i \<=\> f.to\_i}  
> > puts foo
> 
> It’s odd (to me) that #nonzero? doesn’t return true or false, a fact I  
> wasn’t aware of until looking at this (and wondering why it worked 🙂
> 
> David
> 
> –  
> David Alan Black  
> home: [dblack@candle.superlink.net](mailto:dblack@candle.superlink.net)  
> work: blackdav@shu.edu  
> Web: [http://pirate.shu.edu/~blackdav](http://pirate.shu.edu/~blackdav)

---

<div class="post-metadata">

**Author:** ![Ian\_Macdonald](https://avatars.discourse-cdn.com/v4/letter/i/f19dbf/32.png) [@Ian\_Macdonald](https://rubytalk.org/u/Ian_Macdonald)\
**Post date:** [7 August 2002 01:00 UTC](https://rubytalk.org/t/sort-problem/1047/6 "2002-08-07T01:00:24Z")

</div>

> > $/ = nil  
> > foo = gets.split(“\n”)  
> > r = /^([a-z]+)([0-9]+)$/  
> > foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> > e,f = r.match(b)[1,2]  
> > c \<=\> e or d.to\_i \<=\> f.to\_i}  
> > puts foo
> > 
> > [doesn’t work]
> 
> It’s because \<=\> returns -1, 0, or 1, all of which are true in  
> Ruby.

And, of course, I know about those values not returning truth in Ruby,  
but it continues to bite me when I’m least expecting it.

This is one of those few areas where I think the Perl way actually  
makes more sense.

> You could drop in this last line of the sort:
> 
> (c == e) and (d.to\_i \<=\> f.to\_i) or (c \<=\> e)}

Thanks.

Ian

> **···**
>
> ## On Wed 07 Aug 2002 at 09:22:24 +0900, David Alan Black wrote:
> 
> Ian Macdonald | No house should ever be on any hill or on  
> [ian@caliban.org](mailto:ian@caliban.org) | anything. It should be of the hill,  
> \> belonging to it. – Frank Lloyd Wright  
> \>  
> \>

---

<div class="post-metadata">

**Author:** ![Ian\_Macdonald](https://avatars.discourse-cdn.com/v4/letter/i/f19dbf/32.png) [@Ian\_Macdonald](https://rubytalk.org/u/Ian_Macdonald)\
**Post date:** [7 August 2002 06:54 UTC](https://rubytalk.org/t/sort-problem/1047/7 "2002-08-07T06:54:29Z")

</div>

Ah, very elegant indeed! Thanks for this idiom.

Ian

> **···**
>
> On Wed 07 Aug 2002 at 14:31:47 +0900, WATANABE Hirofumi wrote:
> 
> > Ian Macdonald [ian@caliban.org](mailto:ian@caliban.org) writes:
> > 
> > :Ruby  
> > :----  
> > :  
> > :$/ = nil  
> > :foo = gets.split(“\n”)  
> > :r = /^([a-z]+)([0-9]+)$/  
> > :foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> > : e,f = r.match(b)[1,2]  
> > : c \<=\> e or d.to\_i \<=\> f.to\_i}  
> > :puts foo
> > 
> > How about Array#\<=\> ?
> > 
> > [c, d.to\_i] \<=\> [e, f.to\_i]
> 
> –  
> Ian Macdonald | Collaboration, n.: A literary partnership  
> [ian@caliban.org](mailto:ian@caliban.org) | based on the false assumption that the  
> \> other fellow can spell.  
> \>  
> \>

---

<div class="post-metadata">

**Author:** ![GOTO\_Kentaro1](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@GOTO\_Kentaro1](https://rubytalk.org/u/GOTO_Kentaro1)\
**Post date:** [7 August 2002 16:26 UTC](https://rubytalk.org/t/sort-problem/1047/8 "2002-08-07T16:26:29Z")

</div>

And Ruby 1.7 has Array#sort\_by.

foo = foo.sort\_by { |i|  
e,f = r.match(a)[1,2]  
[e, f.to\_i]  
}

By the way, this example reminds me.  
I would sometimes like to modifiy an array in a method chain.  
So, I wrote Array#sub\_at and Array#sub. With this method, above can be  
rewritten as follows:

foo = foo.sort\_by { |i| r.match(a)[1,2].sub\_at(1) { |f| f.to\_i } }

Or the original problem [ruby-talk:46468] can be answered as:

% cat ruby-talk:46468.rb  
require “arraysub”  
puts ARGF.readlines.sort\_by { |line|  
line.scan(/\D+|\d+/).sub(/\d/) { |f| f.to\_i }  
}

% cat ruby-talk:46468.dat  
ina1  
ina15  
inb12  
ina9  
inc10  
inda12  
inef14  
inab14  
inzz8  
inzz80  
inzz9

% ruby17 ruby-talk:46468.rb ruby-talk:46468.dat  
ina1  
ina9  
ina15  
inab14  
inb12  
inc10  
inda12  
inef14  
inzz8  
inzz9  
inzz80

I’ve put arraysub.rb at  
[http://www.notwork.org/~gotoken/ruby/p/as-is/arraysub.rb](http://www.notwork.org/~gotoken/ruby/p/as-is/arraysub.rb)

– Gotoken

> **···**
>
> At Wed, 7 Aug 2002 14:31:47 +0900, WATANABE Hirofumi wrote:
> 
> > :foo = foo.sort {|a,b| c,d = r.match(a)[1,2]  
> > : e,f = r.match(b)[1,2]  
> > : c \<=\> e or d.to\_i \<=\> f.to\_i}  
> > :puts foo
> > 
> > How about Array#\<=\> ?
> > 
> > [c, d.to\_i] \<=\> [e, f.to\_i]

---

<div class="post-metadata">

**Author:** ![David\_Alan\_Black1](https://avatars.discourse-cdn.com/v4/letter/d/278dde/32.png) [@David\_Alan\_Black1](https://rubytalk.org/u/David_Alan_Black1)\
**Post date:** [7 August 2002 17:06 UTC](https://rubytalk.org/t/sort-problem/1047/9 "2002-08-07T17:06:03Z")

</div>

Hi –

> **···**
>
> On Thu, 8 Aug 2002, GOTO Kentaro wrote:
> 
> > And Ruby 1.7 has Array#sort\_by.
> > 
> > foo = foo.sort\_by { |i|  
> > e,f = r.match(a)[1,2]  
> > foo = foo.sort\_by { |i| r.match(a)[1,2].sub\_at(1) { |f| f.to\_i } }
> 
> s/|i|/|a|/g # 🙂
> 
> David
> 
> –  
> David Alan Black  
> home: [dblack@candle.superlink.net](mailto:dblack@candle.superlink.net)  
> work: blackdav@shu.edu  
> Web: [http://pirate.shu.edu/~blackdav](http://pirate.shu.edu/~blackdav)

---

<div class="post-metadata">

**Author:** ![HAL\_9000](https://avatars.discourse-cdn.com/v4/letter/h/90ced4/32.png) [@HAL\_9000](https://rubytalk.org/u/HAL_9000)\
**Post date:** [7 August 2002 17:10 UTC](https://rubytalk.org/t/sort-problem/1047/10 "2002-08-07T17:10:01Z")

</div>

puts “Looks like we’re becoming a forum”  
puts “where we can’t talk at all unless”  
puts “it’s in code or codelike form.”  
puts “:)”

puts “Cheers,\nHal” # Or perhaps Hal.cheers!

> **···**
>
> ----- Original Message -----  
> From: “David Alan Black” [dblack@candle.superlink.net](mailto:dblack@candle.superlink.net)  
> To: “ruby-talk ML” [ruby-talk@ruby-lang.org](mailto:ruby-talk@ruby-lang.org)  
> Sent: Wednesday, August 07, 2002 12:06 PM  
> Subject: Re: sort problem
> 
> > s/|i|/|a|/g # 🙂

---

<div class="post-metadata">

**Author:** ![GOTO\_Kentaro1](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@GOTO\_Kentaro1](https://rubytalk.org/u/GOTO_Kentaro1)\
**Post date:** [7 August 2002 21:27 UTC](https://rubytalk.org/t/sort-problem/1047/11 "2002-08-07T21:27:31Z")

</div>

=begin

> From: “David Alan Black” [dblack@candle.superlink.net](mailto:dblack@candle.superlink.net)  
> To: “ruby-talk ML” [ruby-talk@ruby-lang.org](mailto:ruby-talk@ruby-lang.org)

> > s/|i|/|a|/g # 🙂

> puts “Looks like we’re becoming a forum”  
> puts “where we can’t talk at all unless”  
> puts “it’s in code or codelike form.”  
> puts “:)”
> 
> puts “Cheers,\nHal” # Or perhaps Hal.cheers!  
> =end

%(

Oops! Thank you David for correcting.  
And for cheerful comment, Hal 😃

– Gotoken  
;).

display

> **···**
>
> At Thu, 8 Aug 2002 02:10:01 +0900, Hal E. Fulton [hal9000@hypermetrics.com](mailto:hal9000@hypermetrics.com) wrote:
