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