Syntactic Confectionery Delight PerlMonks

### A generic sorting problem

by frankus (Priest)
 on Jul 19, 2002 at 09:24 UTC Need Help??
frankus has asked for the wisdom of the Perl Monks concerning the following question:

Ok, I've got a piece of code where an array is sorted.
Sometimes the array is all numbers, other times all characters.
The artless way (to me) seemed to be to check the first element and sort depending on that.

What I settled for was a catch-all:

```for my \$line (sort {unpack('C4',\$a) <=> unpack('C4',\$b) } keys %\$value
+) {
tinker_with(\$line);
}

Some of the time the job of the Pack is redundant, other times, not so.
Is there a better way of doing this?

--

Brother Frankus.

¤

Replies are listed 'Best First'.
Re: A generic sorting problem
by demerphq (Chancellor) on Jul 19, 2002 at 10:11 UTC
Well one idea might be this
```sub smart_sort {
my \$obj=shift;
my \$array=UNIVERSAL::isa(\$obj,'HASH') ? [keys %\$obj] : \$obj;
return [ \$array->[0]=~/\D/ ? sort @\$array : sort {\$a <=> \$b} @\$arra
+y ];
}
Other ideas are contained in (Golf) Keysort

By the way, you might want to have a look at Advanced Sorting - GRT - Guttman Rosler Transform as well as the ST by Merlyn and ST by Chromatic

HTH

Yves / DeMerphq
---
Writing a good benchmark isnt as easy as it might look.

Re: A generic sorting problem
by Abigail-II (Bishop) on Jul 19, 2002 at 10:10 UTC
Your "catchall" doesn't seem to catch all:
```use strict;
use warnings 'all';

my @array1 = (1, 2, 3, 4, 5, 15, 14, 13, 12, 11);
my @array2 = sort {unpack('C4',\$a) <=> unpack('C4',\$b)} @array1;
print "@array2\n";
__END__
1 11 14 15 13 12 2 3 4 5
which is just a normal alphabetical sort.

Abigail

Re: A generic sorting problem
by bronto (Priest) on Jul 19, 2002 at 10:50 UTC

A solution could be to take advantage of the possibility to feed sort a reference to a sorting subroutine. That way you could check if the first element is a number (for example with \$array[0] =~ /^\d+\$/ ) and select the right subroutine:

```my @array = (12,23,34,56,876,324,13) ;
# Use the array below to test for alphas
#my @array = qw(mamma ninnonnina domani festa din don dan) ;

my \$sortsub ;
my \$sortnum = sub { \$a <=> \$b } ;
my \$sortalpha =  sub { \$a cmp \$b } ;

\$sortsub = \$array[0] =~ /^\d+\$/ ? \$sortnum : \$sortalpha ;

my @sorted = sort \$sortsub @array ;

print map "\$_\n",@sorted ;

Note however that this approach is far from optimal in this case. In fact when the array contains alphas you replace the fast native sorting with a slower \$sortalpha. This approach is better suited for selecting a sort sub in more complicated sorting.

Ciao!
--bronto

```# Another Perl edition of a song:
# The End, by The Beatles
END {
}```

Re: A generic sorting problem
by choocroot (Friar) on Jul 19, 2002 at 10:17 UTC
I think you should use the cmp and <=> operators in the sort subroutine, like this :
```@a = qw( words only contains );
@b = qw( 8 3 7 1 );

print join( " ", sort { \$a <=> \$b || \$a cmp \$b } @a ), "\n";
# contains only words
print join( " ", sort { \$a <=> \$b || \$a cmp \$b } @b ), "\n";
# 1 3 7 8
This way you can even sort numbers AND letters :
```@a = qw( 2 two 1 one );
print join( " ", sort { \$a cmp \$b || \$a <=> \$b } @a ), "\n";
# 1 2 one two
Your first two examples would raise warnings galore when handling non numeric values, and the second example is simply an alphabetic sort, equivelent to sort @a

```use warnings;
use strict;
my @a = qw( 2 two 1 11 12 one 3abcd 6foo );
print join( " ", sort { \$a <=> \$b || \$a cmp \$b } @a ), "\n";

__END__
Argument "two" isn't numeric in numeric comparison (<=>) at c:\temp\so
+rt.pl line 4.
Argument "one" isn't numeric in numeric comparison (<=>) at c:\temp\so
+rt.pl line 4.
Argument "3abcd" isn't numeric in numeric comparison (<=>) at c:\temp\
+sort.pl line 4.
Argument "6foo" isn't numeric in numeric comparison (<=>) at c:\temp\s
+ort.pl line 4.
one two 1 2 3abcd 6foo 11 12
and
```#...
print join( " ", sort { \$a cmp \$b || \$a <=> \$b } @a ), "\n";

__END__
1 11 12 2 3abcd 6foo one two

Yves / DeMerphq
---
Writing a good benchmark isnt as easy as it might look.

Oops :( you are absolutely right !

But is there a way to do this without getting the warnings messages ? by localizing \$^W I guess ? or simply by not using this kind of construction :)))

Create A New User
Node Status?
node history
Node Type: perlquestion [id://183171]
Approved by grinder
help
Chatterbox?
 talexb is having a hard time with Windows losing DNS info for Perlmonks when voting. CB works fine. Ugh. [jedikaiti]: how odd

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (10)
As of 2017-07-25 15:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
I came, I saw, I ...

Results (374 votes). Check out past polls.