# How to sort this array

**URL:** <https://www.ruby-forum.com/t/how-to-sort-this-array/152182>\
**Category:** Ruby\
**Created:** [October 30, 2008, 10:15pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182 "2008-10-30T22:15:44Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 30, 2008, 10:15pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/1 "2008-10-30T22:15:44Z")

</div>

Hi,

I have an array containing files names. How do I sort them so that I can  
get the expected results?

Thanks,

Li

#############  
files=[  
“c:/ruby/self/2004/20.txt”,  
“c:/ruby/self/2004/3.txt”,  
“c:/ruby/self/2004/2.txt”,  
“c:/ruby/self/2004/10.txt”,  
“c:/ruby/self/2004/1.txt”  
]

expected results:  
[  
“c:/ruby/self/2004/1.txt”,  
“c:/ruby/self/2004/2.txt”,  
“c:/ruby/self/2004/3.txt”,  
“c:/ruby/self/2004/10.txt”,  
]  
“c:/ruby/self/2004/20.txt”,

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 30, 2008, 10:34pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/2 "2008-10-30T22:34:03Z")

</div>

Li Chen wrote:

> Hi,
> 
> I have an array containing files names. How do I sort them so that I can  
> get the expected results?
> 
> Thanks,
> 
> Li
> 
> #############  
> files=[  
> “c:/ruby/self/2004/20.txt”,  
> “c:/ruby/self/2004/3.txt”,  
> “c:/ruby/self/2004/2.txt”,  
> “c:/ruby/self/2004/10.txt”,  
> “c:/ruby/self/2004/1.txt”  
> ]
> 
> expected results:  
> [  
> “c:/ruby/self/2004/1.txt”,  
> “c:/ruby/self/2004/2.txt”,  
> “c:/ruby/self/2004/3.txt”,  
> “c:/ruby/self/2004/10.txt”,  
> ]  
> “c:/ruby/self/2004/20.txt”,

You get that result because in “2” \<=\> “10” the comparison is byte by  
byte and then “2” is \> “1”, so it aborts there with “2” being \> than  
“10”.  
What you want is called natural sorting. Googling for natsort and ruby  
you should get a few results.

Regards  
Stefan

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 30, 2008, 10:44pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/3 "2008-10-30T22:44:27Z")

</div>

here is my code:

C:\Users\Alex\>irb  
irb(main):001:0\> files=[  
irb(main):002:1\* “c:/ruby/self/2004/20.txt”,  
irb(main):003:1\* “c:/ruby/self/2004/3.txt”,  
irb(main):004:1\* “c:/ruby/self/2004/2.txt”,  
irb(main):005:1\* “c:/ruby/self/2004/10.txt”,  
irb(main):006:1\* “c:/ruby/self/2004/1.txt”  
irb(main):007:1\> ]  
=\> [“c:/ruby/self/2004/20.txt”, “c:/ruby/self/2004/3.txt”,  
“c:/ruby/self/2004/2.txt”, “c:/ruby/self/  
2004/10.txt”, “c:/ruby/self/2004/1.txt”]  
irb(main):008:0\>  
irb(main):009:0\*  
irb(main):010:0\* files=files.sort\_by do|s|  
irb(main):011:1\* s.split(///)[-1].split(/./)[0].to\_i  
irb(main):012:1\> end  
=\> [“c:/ruby/self/2004/1.txt”, “c:/ruby/self/2004/2.txt”,  
“c:/ruby/self/2004/3.txt”, “c:/ruby/self/2  
004/10.txt”, “c:/ruby/self/2004/20.txt”]  
irb(main):013:0\>

I am not sure if it is the Rubyish way.

Li

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 30, 2008, 11:32pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/4 "2008-10-30T23:32:19Z")

</div>

On Fri, Oct 31, 2008 at 06:14:51AM +0900, Li Chen wrote:

> files=[  
> “c:/ruby/self/2004/2.txt”,  
> “c:/ruby/self/2004/3.txt”,  
> “c:/ruby/self/2004/10.txt”,  
> ]  
> “c:/ruby/self/2004/20.txt”,

files = files.sort\_by { |f| f[//(\d+).[^/]\*\Z/, 1].to\_i }

There are several things to explain here:

- The #sort\_by method calls the block on each element to produce a set  
of  
surrogate values to use as sorting keys.

- The regular expression captures the series of digits between the last  
slash in a string and the following dot.

- The [] method can be called on String in many ways, including passing  
a  
RegExp and an index. That form returns the capture of the appropriate  
index from matching the RegExp or nil if the RegExp does not match.

- Calling #to\_i on the result means that it will either parse the  
captured  
sequence of digits as an integer or, if the RegExp fails, return 0.

–Greg

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 30, 2008, 11:35pm UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/5 "2008-10-30T23:35:49Z")

</div>

- Li Chen [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) (22:14) schrieb:

> “c:/ruby/self/2004/1.txt”,  
> “c:/ruby/self/2004/2.txt”,  
> “c:/ruby/self/2004/3.txt”,  
> “c:/ruby/self/2004/10.txt”,  
> “c:/ruby/self/2004/20.txt”,  
> ]

files.sort\_by { | fn | fn.match(/(\d+).txt$/)[1].to\_i }

mfg, simon … hth

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 31, 2008, 5:02am UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/6 "2008-10-31T05:02:29Z")

</div>

On Fri, Oct 31, 2008 at 5:14 AM, Li Chen [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> expected results:  
> [ “c:/ruby/self/2004/1.txt”,  
> “c:/ruby/self/2004/2.txt”,  
> “c:/ruby/self/2004/3.txt”,  
> “c:/ruby/self/2004/10.txt”,  
> “c:/ruby/self/2004/20.txt”,  
> ]

apology in advance for dupl email. i sent an email an hrs back but it  
seems it got blackholed 🙂

anyway, if you want basename numeric sorting, then just do

eg,

files.sort\_by{|f| File.basename(f).to\_i}

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 31, 2008, 9:13am UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/7 "2008-10-31T09:13:25Z")

</div>

2008/10/31 botp [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> seems it got blackholed 🙂
> 
> anyway, if you want basename numeric sorting, then just do
> 
> eg,
> 
> files.sort\_by{|f| File.basename(f).to\_i}

Very elegant! Here’s another variant

irb(main):013:0\> puts files.sort\_by {|f| f[/\d+(?=.txt$)/].to\_i}  
c:/ruby/self/2004/1.txt  
c:/ruby/self/2004/2.txt  
c:/ruby/self/2004/3.txt  
c:/ruby/self/2004/10.txt  
c:/ruby/self/2004/20.txt  
=\> nil

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 31, 2008, 9:15am UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/8 "2008-10-31T09:15:11Z")

</div>

And here’s a variant for cases where there are multiple subdirectories:

irb(main):010:0\> puts files.sort\_by {|f| f.scan(/\d+/).map{|x|x.to\_i}}  
c:/ruby/self/2004/1.txt  
c:/ruby/self/2004/2.txt  
c:/ruby/self/2004/3.txt  
c:/ruby/self/2004/10.txt  
c:/ruby/self/2004/20.txt

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [October 31, 2008, 2:24am UTC](https://www.ruby-forum.com/t/how-to-sort-this-array/152182/9 "2008-10-31T02:24:56Z")

</div>

On Oct 30, 2008, at 6:34 PM, Simon K. wrote:

> > expected results:  
> > mfg, simon … hth  
> > Since #to\_i will stop at a non-digit, you could get simpler:

files.sort\_by {|fn| fn[%r{.\*/([^/]+)},1].to\_i }

I tend to use %r{ } when the Regexp deals with / characters.

-Rob

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid
