 Perl: the Markov chain saw PerlMonks

### sorting an array

by Selvakumar (Scribe)
 on Jul 10, 2009 at 07:01 UTC Need Help??

Selvakumar has asked for the wisdom of the Perl Monks concerning the following question:

I have a array like this.
@array=("ch1","ch11","ch2","ch5","ch55","ch16");
i need to sort like
ch1
ch2
ch5
ch11
ch16
ch55

How can i do that?

Replies are listed 'Best First'.
Re: sorting an array
by moritz (Cardinal) on Jul 10, 2009 at 07:10 UTC
A reply falls below the community's threshold of quality. You may see it by logging in.
A reply falls below the community's threshold of quality. You may see it by logging in.
Re: sorting an array
by johngg (Canon) on Jul 10, 2009 at 09:50 UTC

A solution using a Schwartzian Transform.

```knoppix@Knoppix:~\$ perl -le '
@arr = qw{ ch1 ch11 ch2 ch5 ch55 ch16 };
print for
map  { \$_->[ 0 ] }
sort { \$a->[ 1 ] <=> \$b->[ 1 ] }
map  { [ \$_, ( split m{(?<=\D)(?=\d)} )[ 1 ] ] }
@arr;'
ch1
ch2
ch5
ch11
ch16
ch55
knoppix@Knoppix:~\$

I hope this is of interest.

Cheers,

JohnGG

Re: sorting an array
by 1Nf3 (Pilgrim) on Jul 10, 2009 at 07:40 UTC

Sort::Key::Natural seems the best way here, so I'd stick with moritz's suggestion.

But if you want to experiment with sort, it can be done with a custom sort subroutine. An example (tested):

```#!/usr/bin/perl -w
use strict;

sub by_the_number_at_the_end {
\$a =~ /(\d+)\$/;
my \$end_of_a = \$1;
\$b =~ /(\d+)\$/;
my \$end_of_b = \$1;
return -1 if \$end_of_a < \$end_of_b;
return 0  if \$end_of_a == \$end_of_b;
return 1  if \$end_of_a > \$end_of_b;
}

my @array=("ch1","ch11","ch2","ch5","ch55","ch16");

print join ("\n", sort by_the_number_at_the_end @array);

Regards,
Luke

Re: sorting an array
by ELISHEVA (Prior) on Jul 10, 2009 at 08:08 UTC

Sort::Key::Natural will do the trick assuming you can use CPAN (see Yes, even you can use CPAN for tips on how), but there are a couple concepts here that are probably worth learning in any case:

sort lets you define a custom sort routine, like this:
```use strict;
use warnings;

my @aChapters=("ch1","ch11","ch2","ch5","ch55","ch16");
my @aSorted = sort {
my (\$sA, \$iA) = (\$a =~ /(^[^\d]+)(\d+)/);
my (\$sB, \$iB) = (\$b =~ /(^[^\d]+)(\d+)/);
my \$x = \$sA cmp \$sB;
(\$x = \$iA <=> \$iB) unless \$x;
\$x;
} @aChapters;

local \$"="\n";
print "@aSorted";

\$a and \$b are special variables that represent the two members of the list you want to sort. The main trick here is to (i) split your name into two parts: an alpha part and a numeric part (ii) compare the alpha part using the alpha comparison operator (cmp) and the numeric part using the numeric comparison operator (<=>). See perlop for more information.

Best, beth

Re: sorting an array
by cdarke (Prior) on Jul 10, 2009 at 10:53 UTC
Given the simple nature of the data, i.e. each element startswith 'ch', I'm surprised others didn't do this:
```my @sorted = sort { substr(\$a,2) <=> substr(\$b,2) } @array;
OK, so it's calling substr rather a lot of times, so with a large array that might be slow. Alternatively we could cache it:
```@array = map {substr(\$_,2)} @array;
my @sorted = sort { \$a <=> \$b } @array;
@sorted = map { "ch\$_" } @sorted;
Re: sorting an array
by JavaFan (Canon) on Jul 10, 2009 at 10:59 UTC
```map {"ch\$_"} sort {\$a <=> \$b} map {/(\d+)/} @array
should do.
Re: sorting an array
by missingthepoint (Friar) on Jul 10, 2009 at 09:09 UTC
```# first num
sub num_from_str {
my \$str = shift;
my (\$num) = \$str =~ /(\d+)/;
return \$num;
}
my @a = qw( ch1 ch11 ch55 ch5 ch2 ch16 );
my @sorted = sort { num_from_str(\$a) <=> num_from_str(\$b) } @a;
print "\$_\n" for @sorted;

update: ... but Sort::Key::Natural is a more complete solution, because it sorts based on the alphabetical bits as well.

The zeroeth step in writing a module is to make sure that there isn't already a decent one in CPAN. (-- Pod::Simple::Subclassing)
Re: sorting an array
by pKai (Priest) on Jul 10, 2009 at 11:59 UTC
```map {'ch'.(0+\$_)} sort map {sprintf "%.10u", /(\d+)/} @array;

just for the sake of using a technique of Advanced Sorting - GRT - Guttman Rosler Transform, i.e. make a map sort map but with a bare/string sort.

Of course, a pack 'N' would be preferable over the sprintf.

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://778819]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2022-05-26 11:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Do you prefer to work remotely?

Results (93 votes). Check out past polls.

Notices?