Monolith-0 has asked for the wisdom of the Perl Monks concerning the following question:

I want to get the sorted order of a list of values, but not change the original list. I have an index array in which I wish keep track of the values' sorted order.

For example... start with:

@stuff_list = ( 'b','t','e','s','u','i' ); @list_order = ( 0 , 1 , 2 , 3 , 4 , 5 );
then sort and get:
@stuff_list = ( 'b','t','e','s','u','i' ); @list_order = ( 0 , 2 , 5 , 3 , 1 , 4 );
And then use @list_order to access the actual values.

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: How do I sort into an index?
by Monolith-0 (Beadle) on Feb 24, 2001 at 05:41 UTC
    @list_order = sort { $stuff_list[$a] cmp $stuff_list[$b] } 0 .. $#stuf +f_list;
    Then you can do stuff like the following to see the results:
    for my $i ( 0 .. $#list_order ) { print "$stuff_list[$list_order[$i]]\n"; }
    or
    print join( "\n", @stuff_list[@list_order] ), "\n";
Re: How do I sort into an index?
by tye (Sage) on Feb 23, 2001 at 11:20 UTC
Re: How do I sort into an index?
by Soul Singin' (Initiate) on Sep 13, 2010 at 07:36 UTC
    Original Array: 14 11 10 13 11 New Positions: 4 1 0 3 2 Ordered Array: 10 11 11 13 14 Original Positions: 2 1 4 3 0

    Here's the inelegant code I used to do it:

    #!/usr/bin/env perl ## script to practice creating numeric orderings use strict ; use warnings ; ## we want to find the POSITION of each value after ordering my @values = ( 14 , 11 , 10 , 13 , 11 ) ; ## now let's do some ordering! my %orderings = order( @values ) ; ## ## print original array and positions after ordering print "\n Original Array: " ; foreach my $value ( @values ) { print sprintf( "% 4d" , $value ) ; } print "\n New Positions: " ; foreach my $ordering ( @{ $orderings{ "new_pos" } } ) { print sprintf( "% 4d" , $ordering ) ; } print "\n" ; ## ## print ordered array and original positions print "\n Ordered Array: " ; foreach my $ordering ( @{ $orderings{ "orig_pos" } } ) { print sprintf( "% 4d" , $values[ $ordering ] ) ; } print "\n Original Positions: " ; foreach my $ordering ( @{ $orderings{ "orig_pos" } } ) { print sprintf( "% 4d" , $ordering ) ; } print "\n\n" ; ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## sub order { my @inarray = @_ ; ## elements of @inarray MUST be numeric foreach my $inval (@inarray) { if ( ! is_float( $inval ) ) { die "Fatal error. All elements of the \"order\" subroutine mus +t be numeric." ; } } my @sorted = sort { $a <=> $b } @inarray ; ## make backups my @inarray_bkp = @inarray ; my @sorted_bkp = @sorted ; ## now get original and new positions -- store in hash of arrays my %orderings ; ## get the original positions for my $i (0..$#sorted) { for my $j (0..$#inarray) { if ( $sorted[$i] eq $inarray[$j] ) { ## return the original position push( @{ $orderings{ "orig_pos" } } , $j ) ; ## disqualify as future candidates $sorted[$i] = "AA" ; $inarray[$j] = "ZZ" ; } } } ## restore from backups @inarray = @inarray_bkp ; @sorted = @sorted_bkp ; ## get the new positions for my $i (0..$#inarray) { for my $j (0..$#sorted) { if ( $inarray[$i] eq $sorted[$j] ) { ## return the new position push( @{ $orderings{ "new_pos" } } , $j ) ; ## disqualify as future candidates $inarray[$i] = "AA" ; $sorted[$j] = "ZZ" ; } } } ## return the original and new positions return %orderings ; } sub is_float { my $inval = $_[0] ; defined $inval && $inval =~ /^[+-]?\d+(\.\d+)?$/; }

    Originally posted as a Categorized Answer.

Re: How do I sort into an index?
by Soul Singin' (Initiate) on Sep 14, 2010 at 02:26 UTC

    Here's the elegant solution I was looking for! The following results:

    Original Array: 14 11 10 13 11 New Positions: 4 1 0 3 2 Ordered Array: 10 11 11 13 14 Original Positions: 2 1 4 3 0

    Can be obtained from:

    #!/usr/bin/env perl ## script to practice creating numeric orderings use strict ; use warnings ; ## we want to find the POSITION of each value before and after orderin +g my @values = ( 14 , 11 , 10 , 13 , 11 ) ; ## now let's do some ordering! my %orderings = order( @values ) ; ## ## print original array and positions after ordering print "\n Original Array: " ; foreach my $value ( @values ) { print sprintf( "% 4d" , $value ) ; } print "\n New Positions: " ; foreach my $ordering ( @{ $orderings{ "new_pos" } } ) { print sprintf( "% 4d" , $ordering ) ; } print "\n" ; ## ## print ordered array and original positions print "\n Ordered Array: " ; foreach my $ordering ( @{ $orderings{ "orig_pos" } } ) { print sprintf( "% 4d" , $values[ $ordering ] ) ; } print "\n Original Positions: " ; foreach my $ordering ( @{ $orderings{ "orig_pos" } } ) { print sprintf( "% 4d" , $ordering ) ; } print "\n\n" ; ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## sub order { my @inarray = @_ ; ## elements of @inarray MUST be numeric foreach my $inval (@inarray) { if ( ! is_float( $inval ) ) { die "Fatal error. All elements of the \"order\" subroutine mus +t be numeric." ; } } ## get the original positions my %pos_orig ; for my $i (0..$#inarray) { push( @{ $pos_orig{ $inarray[$i] }} , $i ) ; } ## put original positions into an array my @orig ; foreach my $key ( sort { $a <=> $b } keys %pos_orig ) { push( @orig , @{ $pos_orig{ $key }} ) ; } ## get the new positions my @sorted = sort { $a <=> $b } @inarray ; my %pos_new ; for my $i (0..$#sorted) { push( @{ $pos_new{ $sorted[$i] }} , $i ) ; } ## put new positions into an array my @new ; foreach my $key ( @inarray ) { push( @new , shift( @{ $pos_new{ $key }} )) ; } ## return the original and positions -- as hash of arrays my %orderings ; @{ $orderings{ "orig_pos" }} = @orig ; @{ $orderings{ "new_pos" }} = @new ; return %orderings ; } sub is_float { my $inval = $_[0] ; defined $inval && $inval =~ /^[+-]?\d+(\.\d+)?$/; }

    Originally posted as a Categorized Answer.

Re: How do I sort into an index?
by 2501 (Pilgrim) on Feb 23, 2001 at 18:12 UTC
    use a hash where the key is your sort order and the value is what you would have put in your "value array".

    Originally posted as a Categorized Answer.