In class someone asked about sorting an array, but preserving the information about where a value had come from in the source array. For examples, given the array:
| Index | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| Value | 'e' | 'c' | 'a' | 'b' | 'd' |
we should be able to output:
0. a (came from 2) 1. b (came from 3) 2. c (came from 1) 3. d (came from 4) 4. e (came from 0)
This program does exactly that, in several different ways. This is by no means exhaustive, but it covers a number of techniques.
#! /usr/bin/perl
use strict;
use warnings;
my(@input) = ('e','c','a','b','d');
# This is the solution I created on the chalkboard in class:
my @indices = 0..(scalar(@input) - 1);
my(@sorted_indices) = sort { $input[$a] cmp $input[$b] } @indices;
for(my $i = 0; $i < @sorted_indices; $i++) {
my $original_index = $sorted_indices[$i];
my $value = $input[$original_index];
print "$i. $value (came from $original_index)\n";
}
print "---\n";
# Someone asked about using a hash. There are two options.
# We can implement the solution above, but using a hash. It doesn't
# get us much.
my %input;
for(my $i = 0; $i < @input; $i++) {
$input{$i} = $input[$i];
}
@sorted_indices = sort { $input{$a} cmp $input{$b} } keys %input;
for(my $i = 0; $i < @sorted_indices; $i++) {
my $original_index = $sorted_indices[$i];
my $value = $input{$original_index};
print "$i. $value (came from $original_index)\n";
}
print "---\n";
# We can put the values in the keys of the hash. This might make the code more
# straightforward, but fails if the same value appears in the array twice!
%input = (); # Reset hash
for(my $i = 0; $i < @input; $i++) {
if(exists $input{$input[$i]}) {
die "FATAL ERROR: $input[$i] appears twice in this array and it can not be represented!";
}
$input{$input[$i]} = $i;
}
my @sorted_values = sort keys %input;
for(my $i = 0; $i < @sorted_values; $i++) {
my $value = $sorted_values[$i];
my $original_index = $input{$value};
print "$i. $value (came from $original_index)\n";
}
print "---\n";
# Finally, we might store the original index alongside the data.
my @input_pairs;
for(my $i = 0; $i < @input; $i++) {
$input_pairs[$i] = [$input[$i], $i];
}
my @sorted_pairs = sort { $a->[0] cmp $b->[0] } @input_pairs;
for(my $i = 0; $i < @sorted_pairs; $i++) {
my $value = $sorted_pairs[$i][0];
my $original_index = $sorted_pairs[$i][1];
print "$i. $value (came from $original_index)\n";
}
print "---\n";