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

here is the problem.   i have an array lets say like this

$arr1[0] = "john:::10"; $arr1[1] = "bill:::9"; $arr1[2] = "mary:::35"; $arr1[3] = "willy:::21";

and another array containing the second element of @arr1 :

$arr2[0] = 10; $arr2[1] = 9; $arr2[2] = 35; $arr2[3] = 21;

i want to sort @arr1 according to @arr2 sorting.   that means that after the execution i ll have @arr1 like this :

$arr1[0] = "bill:::9"; $arr1[1] = "john:::10"; $arr1[2] = "willy:::21"; $arr1[3] = "mary:::35";

i want to do all this by using only the sort command..
thanx in advance

janitored by ybiC: Removed bogo<br> tags within <code>block. Also minor format tweaks for legibility

Replies are listed 'Best First'.
Re: Sort array1 according to sorting of array2
by I0 (Priest) on Aug 26, 2004 at 05:50 UTC
    @arr1=@arr1[sort{$arr2[$a]<=>$arr2[$b]}0..$#arr2];

      Yup, this is how I'd do it (maybe with a touch more whitespace). I'd expect this also to be more efficient than any approach splitting the numbers out of @arr1 again, though not necessarily better than switching to different ways of structuring the data.

      Hugo

Re: Sort array1 according to sorting of array2
by ikegami (Patriarch) on Aug 26, 2004 at 05:10 UTC

    I don't think it's possible using just the builtin sort commmand. What about:

    # First, sort @arr1. @arr1 = sort { my ($c) = $a =~ /:::(\d+)$/; my ($d) = $b =~ /:::(\d+)$/; +$c <=> +$d } @arr1; # Then recreate @arr2. @arr2 = map { s/^.*:::(\d+)$/$1/ } @arr1;

    or:

    @arr3 = sort { $a->[1] <=> $b->[1] } map { [ $arr1[$_], $arr2[$_] ] } (0..$#arr1); @arr1 = map { $_->[0] } @arr3; @arr2 = map { $_->[1] } @arr3;
Re: Sort array1 according to sorting of array2
by revdiablo (Prior) on Aug 26, 2004 at 05:26 UTC
    i want to sort @arr1 according to @arr2 sorting

    Your example output doesn't really match what you describe. It appears you just want @arr1 sorted according to the numeric value. If that's the case, then ikegami has answered your question. If, instead, you actually want what you describe -- @arr1 sorted according to the order in @arr2 -- then something like this might work:

    #!/usr/bin/perl -l use strict; use warnings; my @arr1 = qw(john:::10 bill:::9 mary:::35 willy:::21); my @arr2 = qw(9 35 10 21); my $i = 0; my %order = map { $_ => $i++ } @arr2; print for sort { my ($c) = $a =~ /:::(\d+)$/; my ($d) = $b =~ /:::(\d+)$/; $order{$c} <=> $order{$d} } @arr1;

    Notice I used a hash to store the order of each element from @arr2. This is for efficiency -- you could do a search through @arr2 each time, but that wouldn't scale very well.

      thanx guys,
      my mistake revdiablo, i actually needed what ikegami proposed..,
      but your code could be usefull to me in the future..,
      ,
      thanx again,
      Or, I just faced that very problem here (Ordering objects using external index). The one you derived from original question in this thread. I think that my method is a little faster than yours but not that fast that I'd expect anyway.
      #!/usr/bin/perl use strict; use warnings; my @arr1 = qw(john:::10 bill:::9 mary:::35 willy:::21); my @arr2 = qw(9 35 10 21); my %hash = map { $_ =~ /:::(\d+)$/; ($1 => \$_); } @arr1; print for map { $$_ } @hash{@arr2};
      No sorts. References are optional, of course.
Re: Sort array1 according to sorting of array2
by NetWallah (Canon) on Aug 26, 2004 at 05:43 UTC
    Here is a way using the sort ..
    You do not need @arr2 .
    use strict; my (@arr1); $arr1[0] = "john:::10"; $arr1[1] = "bill:::9"; $arr1[2] = "mary:::35"; $arr1[3] = "willy:::21"; ##################### sub comparesimple { (split /:/,$a)[-1] # Take last element of split.. <=> # Do numeric compare (split /:/,$b )[-1] } ############################## print qq($_ \n) for sort comparesimple @arr1;

        Earth first! (We'll rob the other planets later)

Re: Sort array1 according to sorting of array2
by BrowserUk (Patriarch) on Aug 26, 2004 at 05:43 UTC

    It's a long way around to do it, but maybe you have your reasons.

    #! perl -slw use strict; use Data::Dumper; my @array1 = ( "john:::10", "bill:::9", "mary:::35", "willy:::21", ); ## Build @array2 from the numbers in @array1 my @array2 = map{ m[(\d+)$] and $1 } @array1; ## Reorder @array1 by assigning a slice across it ## with the indexes sorted according to the numeric values in @array2 @array1 = @array1[ sort { $array2[ $a ] <=> $array2[ $b ] } 0 .. $#arr +ay2 ]; print Dumper \@array1; __END__ P:\test>385906 $VAR1 = [ 'bill:::9', 'john:::10', 'willy:::21', 'mary:::35' ];

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Sort array1 according to sorting of array2
by saintmike (Vicar) on Aug 26, 2004 at 05:43 UTC
    How about mix of map and sort:
    my $idx; my @sorted = map { $arr1[$_->[0]] } sort { $a->[1] <=> $b->[1] } map { [$idx++, $_] } @arr2;
Re: Sort array1 according to sorting of array2
by johnnywang (Priest) on Aug 26, 2004 at 05:55 UTC
    Here's my version:
    #!/usr/bin/perl -l use strict; use warnings; my @arr1 = qw(john:::10 bill:::9 mary:::35 willy:::21); my @arr2 = qw(10 9 35 21); my %map = map {$arr1[$_]=>$arr2[$_]} (0 .. $#arr1); @arr1 = sort{$map{$a}<=>$map{$b}} keys %map; print join("\n",@arr1); __END__ bill:::9 john:::10 willy:::21 mary:::35
Re: Sort array1 according to sorting of array2
by davido (Cardinal) on Aug 27, 2004 at 00:22 UTC

    Here's a basic Schwartzian Transform solution to an example problem that is very similar to yours.

    my @array1 = qw/this that those these/; my @array2 = qw/2 3 1 4/; my @sorted = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map { [$array2[$_] , $array1[$_]] } 0 .. $#array2; { local $" = "\t"; print "@array1\n"; print "@sorted\n"; }

    Hope this helps...


    Dave