sort-array.pl

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:

Index01234
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";