in reply to Restore the original order of an array after sort and performing some funchtion on array values

Sort the indexes and apply your operations in that order without actually changing the ordering of the array:

#! perl -slw use strict; my @array = (2.5 ,4.8, 3.2, 8.5, 8.2, 12.5); my @orderedIndexes = sort{ $array[ $b ] <=> $array[ $a ] } 0 .. $#array; my $n = @array; $array[ $_ ] *= @array / $n-- for @orderedIndexes; print "@array"; __END__ c:\test>junk68 15 9.6 9.6 10.2 12.3 12.5

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"I'd rather go naked than blow up my ass"
  • Comment on Re: Restore the original order of an array after sort and performing some funchtion on array values
  • Download Code

Replies are listed 'Best First'.
Re^2: Restore the original order of an array after sort and performing some funchtion on array values
by Anonymous Monk on Mar 03, 2010 at 18:00 UTC
    Definitely the way to go.

    For a lot of stuff, perl's list munging capabilities are much better/straightforward than dealing with array indices.

    The problem at hand is one of the few instances to NOT take advantage of perl's list-centric features and work with the indices directly.

    -Greg

Re^2: Restore the original order of an array after sort and performing some funchtion on array values
by sesemin (Beadle) on Mar 03, 2010 at 18:06 UTC
    Thanks For the quick response. To simplify my question I used an array as an example.

    Can I use the same concept on a hash value? Let's say I want to perform the same operation on values of the hash and return the sorted keys with new data. For instance:

    #!/usr/local/bin/perl use strict; my %pvalues = ( 1=> 0.5453980, 2=> 0.4902384, 3=> 0.8167950, 4=> 0.2821822, 5=> 0.4693030, 6=> 0.6491767, 7=> 0.9802138, 8=> 0.1155778, 9=> 0.9585124, 10=> 0.4069490 );

    They keys of course are unique but the values may not. I have done the following.

    my $numberPvalues = scalar keys %pvalues; my $numberPvaluesCounter = scalar keys %pvalues; my $numberPos = 0; # now loop through all p values and calculate FDR value # store FDR values in hash, key = pos, value is FDRq my @reversPvalues =(); my %sortedTransfPvalues =(); my @inversPvalue =(); my @cumulminPvalue =(); while ($numberPvaluesCounter >= 1 ){ #Sort the original pvalue hash based on the values descen +ding manner foreach my $posCurrentPvalue (sort {$pvalues{$b} <=> $pva +lues{$a}} keys %pvalues) { #calculate the transformed pvalues based on its rank + in the sorted value in the hash my $transformedPvalue = $pvalues{$posCurrentPvalue} +* $numberPvalues / $numberPvaluesCounter; $numberPvaluesCounter--; #new indcies $numberPos++; push (@inversPvalue, $transformedPvalue); #$sortedTransfPvalues{$numberPos}{$posCurrent +Pvalue} = $transformedPvalue; #$sortedTransfPvalues{$posCurrentPvalue}{$num +berPos} = $transformedPvalue; print "$posCurrentPvalue\t$transformedPvalue\ +n"; }#end foreach and sorting values }#end while for count down
      Can I use the same concept on a hash value?

      Yes. In exactly analogous fashion. Order the keys by value and then process your values in that order:

      #!/usr/local/bin/perl use strict; use Data::Dump qw[ pp ]; my %pvalues = ( 1=> 0.5453980, 2=> 0.4902384, 3=> 0.8167950, 4=> 0.2821822, 5=> 0.4693030, 6=> 0.6491767, 7=> 0.9802138, 8=> 0.1155778, 9=> 0.9585124, 10=> 0.4069490 ); my @orderedKeys = sort { $pvalues{ $b } <=> $pvalues{ $a } } keys %pvalues; my $d = my $n = values %pvalues; $pvalues{ $_ } *= $n / $d-- for @orderedKeys; pp \%pvalues; __END__ c:\test>junk68 { 1 => "0.908996666666667", 2 => "0.9804768", 3 => "1.02099375", 4 => "1.410911", 5 => "1.1732575", 6 => "0.927395285714286", 7 => "0.9802138", 8 => "1.155778", 9 => "1.06501377777778", 10 => "1.35649666666667", }

      Of course, hash keys aren't intrinsically ordered, so you'll have to order them as needed for output, but one of the structure dumpers will do that for you.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Thanks for helping to solve this problem. For my final implementation of p.adjust function from R in Perl I need to provide you the entire algorithm. Basically you have solved a lot of it. I do not have any problem with section (d), but based on what I was thinking and you implemented the order that I get at (c) is different from what it should be. </code>

        (a) sort these values in an decreasing order

        0.9802138 0.9585124 0.8167950 0.6491767 0.5453980 0.4902384 0.4693030 0.4069490 0.2821822 0.1155778

        (b) assign order to each above observation in a decreasing order, i.e.,

        10 9 8 7 6 5 4 3 2 1

        (c) then calculate

        0.9802138*10/10 0.9585124*10/9 0.8167950*10/8 ..... 0 .1155778*10/1 (note that: the 10 in the numerator corresponds to the total number of tests conducted in this toy example, you should change this to the corresponding actual number of tests when you do real data analysis. Also the order assignment will start with the total number of tests and decrease to 1.)

        You will obtain the following

        0.9802138 1.0650138 1.0209938 0.9273953 0.9089967 0.9804768 1.1732575 1.3564967 1.4109110 1.1557780

        (d) then do the the cumulative minimum adjustment, i.e.

        since 0.9802138<1.0650138, replace 1.0650138 with 0.9802138,

        then among the first three values 0.9802138, 0.9802138, 1.0209938, 0.9802138 is smallest, replace 1.0209938 with 0.9802138

        then among the first four values 0.9802138, 0.9802138, 0.9802138, 0.9273953, 0.9273953 is the smallest, and the fourth value will not be changed

        similarly, the fifth value will not be changed and all the rest of values will be changed to 0.9089967

        Finally you should have 0.9802138, 0.9802138, 0.9802138, 0.9273953 0.9089967 0.9089967 0.9089967 0.9089967 0.9089967 0.9089967

        rearrange these value according to the original order of p-value,

        0.5453980 0.4902384 0.8167950 0.2821822 0.4693030 0.6491767 0.9802138 0.1155778 0.9585124 0.4069490

        [6] [5] [8] [2] [4] [7] [10] [1] + [9] [3]

        then you will obtain the following values

        0.9089967 0.9089967 0.9802138 0.9089967 0.9089967 0.9273953 0.9802138 0.9089967 0.9802138 0.9089967

        then you compare each of these values (in red) with 1, if it is greater than 1, then replace that value with 1. Since in this particular example, all the above values (in red) are less than 1, your final BH adjusted q-values are

        0.9089967 0.9089967 0.9802138 0.9089967 0.9089967 0.9273953 0.9802138 0.9089967 0.9802138 0.9089967