Re: How do I record in what order a sort was preformed
by Masem (Monsignor) on Jan 17, 2002 at 23:10 UTC
|
Sort the array, but use the index as the sorting element:
my @sorted_indices = sort { $array[$a] <=> $array[$b] } (0..$#array);
# If you need to get back the sorted array, use this
# without the extra sort step.
my @sorted_array = map { $array[$_] } @sorted_indices;
Update fixed slight problem in first line of code
-----------------------------------------------------
Dr. Michael K. Neylon - mneylon-pm@masemware.com
||
"You've left the lens cap of your mind on again, Pinky" - The Brain
"I can see my house from here!"
It's not what you know, but knowing how to find it if you don't know that's important
| [reply] [d/l] |
|
|
| [reply] [d/l] |
Re: How do I record in what order a sort was preformed
by demerphq (Chancellor) on Jan 17, 2002 at 23:54 UTC
|
Well, it would appear Masem and I have interpreted the question differently.
UPDATE: Erk. No we didnt. /me removes lenscap from eyes. Read Masems reply to my post below. OTOH introducing the ST is never a bad thing, just perhaps not the most appropriate thing ;-)
My interpretation is that you want to sort the list, but be able to determine the elements original positions afterwards. The way to do this is a twist on the Schwartzian Transform.
Basically the idea being that you transform the list into an intermediate form, one that holds the meta info you need, sort as normal and then either use the meta version and or unpack it into the sorted form.
use strict;
use warnings;
my @array=qw(Q W E R T Y U I O P);
my @sorted_meta=sort { $a->[0] cmp $b->[0] } map { [ $array[$_] , $_ ]
+ } 0..$#array;
my @sorted=map { $_->[0] } @sorted_meta;
local $,=" ";
local $\="\n";
print "Orig: ",@array;
print "Meta: ",map { ("[",@{$_},"]") } @sorted_meta;
print "Sort: ",@sorted;
__END__
Outputs:
Orig: Q W E R T Y U I O P
Meta: [ E 2 ] [ I 7 ] [ O 8 ] [ P 9 ] [ Q 0 ] [ R 3 ] [ T 4 ] [ U 6 ]
+ [ W 1 ] [ Y 5 ]
Sort: E I O P Q R T U W Y
I took the liberty of making the list be letters so that the output would be clearer. It need not be so by simply changing the 'cmp' into a '<=>'. Actually on that thought you didnt need the int in your sort routine (perl almost always handles those kind of things in a DWIM fashion)
Anyway, hope one of us has managed to answer the question you were asking.. :-)
Yves / DeMerphq
--
When to use Prototypes? | [reply] [d/l] |
|
|
You're going to get the ability to get the same result in either fashion. However, for my reply to a similar question on array sorting, merlyn pointed out that the ST is overly heavy for the sorting, and the method that I suggested above was better for getting the sorted indices. Now, with mine, you can rebuild the sorted array via the map I provided, but it's just as easy to do this as well:
@sorted_indices = sort {...} (0..$#array); # as above
@sorted_array = map { $array[$_] } @sorted_indices; #as above
my @to_position;
$to_position[ sorted_indices[ $_ ] ] = $_ foreach (0..$#array); # thi
+s is new
IMO, I believe this is more lightweight and a bit easier to follow for the given code than using the heavier ST for the same. Not that the ST can't be useful in a similar situation if the comparison values are heavy in terms of calculation times, but here they defintely aren't.
-----------------------------------------------------
Dr. Michael K. Neylon - mneylon-pm@masemware.com
||
"You've left the lens cap of your mind on again, Pinky" - The Brain
"I can see my house from here!"
It's not what you know, but knowing how to find it if you don't know that's important
| [reply] [d/l] |
Re: How do I record in what order a sort was preformed
by redsquirrel (Hermit) on Jan 18, 2002 at 00:17 UTC
|
Here's another way. Might not be as good as the examples above, but in the spirit of TMTOWTDI...
my $count = 0;
my %hash = map {$_, $count++} @array;
my @sort = sort { int($a) <=> int($b) } @array;
my $flag = 0;
for (@sort) {
print ', ' if $flag++;
print qq|"$_" came from | . '$array[' . $hash{$_} . ']';
}
--Dave | [reply] [d/l] |
|
|
Great code! I did notice however that it doesn't allow for
duplicate numbers :^(
So I revised it ever so slightly to be:
my $count = 0;
my %hash = map {$count++, $_} @array;
my @sort = sort { int($a) <=> int($b) } @array;
my $flag = 0;
for (keys %hash) {
print ', ' if $flag++;
print qq|"$hash{$_}" came from | . '$array[' . $_ . ']';
}
| [reply] [d/l] |
Re: How do I record in what order a
by strat (Canon) on Jan 17, 2002 at 23:09 UTC
|
You could perhaps use a second dimension to keep track where the element came from...
@array = (3,2,1);
$array[4] = 0;
my $i = 0;
foreach (
sort { $a->[1] cmp $b->[1] } # or better <=> for numbers ins
+tead of cmp
map { [$i++, $_ ] } @array
){
my $number = $_->[1];
my $originalIndex = $_->[0];
# do something with $number and $originalIndex...
} # foreach
Best regards,
perl -e "print a|r,p|d=>b|p=>chr 3**2 .7=>t and t" | [reply] [d/l] [select] |
Re: How do I record in what order a sort was preformed
by nandeya (Monk) on Jan 18, 2002 at 02:25 UTC
|
Always a million ways to skin a cat (esp. in this case), and here is another...
#initialize array
@array = (12,7,4);
$i=0;
foreach (@array) {
#Throw in a hash to look up in a second
$hash{$_} = $i;
$i++;
}
#sort it, loop through, and look up from hash from above
foreach (@num_sorted_array = sort { $a <=> $b } @array) {
print "$_ came from \$array\[$hash{$_}\]\n";
}
Probably not the most efficient way, but simple enough.
Regards,
nandeya
| [reply] [d/l] |
|
|
This doesn't allow for duplicate values in the array, the
hash value will get changed to the highest number matched.
See my earlier post for a version that allows for duplicates.
I am also not sure if the fact duplicates aren't handled are
a concern to the original poster, I just know I have been
bitten by this before. :^)
Sorry I didn't take the time to see if your code be modified
to allow for dups.
| [reply] |
Re: How do I record in what order a
by nandeya (Monk) on Jan 18, 2002 at 01:25 UTC
|
Always a million ways to skin a cat, and here is yet another...
#initialize array
@array = (12,7,4);
$i=0;
foreach (@array) {
#Throw in a hash to look up in a second
$hash{$_} = $i;
$i++;
}
#sort it, loop through, and look up from hash from above
foreach (@num_sorted_array = sort { $a <=> $b } @array) {
print "$_ came from \$array\[$hash{$_}\]\n";
}
Probably not the most efficient way (as I loop through array twice and throw into / lookup to a hash), but simple enough.
Regards,
nandeya | [reply] [d/l] |