http://www.perlmonks.org?node_id=539144

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

Greetings monks.

I have a problem in sorting a array. If array contains both digits & characters. my array is like

@a = qw/1x1 1x12 12x3 10x1 4x12 4x1 1x1 22x3 2x1 4x0 12x1 1x2/;

Is there any way to sort this.

Replies are listed 'Best First'.
Re: how to sort this?
by ikegami (Pope) on Mar 25, 2006 at 05:41 UTC

The following sorts numerically by the number preceeding the 'x', then numerically by the number following the 'x':

@a = sort { my (\$a1, \$a2) = split(/x/, \$a); my (\$b1, \$b2) = split(/x/, \$b); \$a1 <=> \$b1 || \$a2 <=> \$b2 } @a;

The OP said the elements contain "both digits & characters", which I assume means (one or more digits) followed by (one or more alpha chars) followed by (one or more digits). If that's the case, ikegami's sort routine can be generalized to include the alpha component:

@a = sort { my (\$a1, \$a2, \$a3) = ( \$a =~ m/(\d+)(\D+)(\d+)/ ); my (\$b1, \$b2, \$b3) = ( \$b =~ m/(\d+)(\D+)(\d+)/ ); \$a1 <=> \$b1 || \$a2 cmp \$b2 || \$a3 <=> \$b3 } @a;

The OP wasn't clear about the specifics, though. If there really is just a single 'x' between the digit portions (and it's always an 'x'), the generalization isn't needed. If by "characters" the OP meant "any character" (as opposed to only alpha chars), then things get more complex.

Re: how to sort this?
by johngg (Canon) on Mar 25, 2006 at 12:09 UTC
An alternative for those who like Schwartzian Transforms.

@a = map {\$_->} sort {\$a-> <=> \$b-> || \$a-> <=> \$b->} map {[\$_, split /x/]} @a;

Cheers,

JohnGG

Re: how to sort this?
by saintmike (Vicar) on Mar 25, 2006 at 05:48 UTC
What do you want to sort it by? Sort it like strings? Like numbers? By extracted integers? Or a combination of all of the above?

Helps to know the requirements before starting an implementation.

hi saint,

my requirement is to sort by integers. also i need the output as

@a = (1x1 1x1 1x2 1x12 2x1 4x0 4x1 4x12 10x1 12x1 12x3 22x3);

Thanks

Hi sen try this it gives your exact output,

#!/usr/local/bin/perl @a1 = qw/1x1 1x12 12x3 10x1 4x12 4x1 1x1 22x3 2x1 4x0 12x1 1x2/; @out = sort { (split 'x', \$a, 2) <=> (split 'x', \$b, 2) } sort { (split 'x', \$a, 2) <=> (split 'x', \$b, 2) }@a1; print "@out";
Re: how to sort this?
by salva (Abbot) on Mar 25, 2006 at 11:19 UTC
use Sort::Key::Maker iikeysort => qw(integer integer); @sorted = iikeysort { /^(\d+)x(\d+)\$/ } @a;
update: and now even simpler:
use Sort::Key::Multi 'iikeysort'; @sorted = iikeysort { /^(\d+)x(\d+)\$/ } @a;
or if the chars between the two numbers can vary:
use Sort::Key::Multi 'isikeysort'; @sorted = isikeysort { /^(\d+)(\w+)(\d+)\$/ } @a;