perlquestion
davidj
Fellow monks,<p>
The following question may sound like homework, but I assure you, it is not.<p><p>
I have a situation where I need to swap columnar data in a 2-dimensional array. There are 3 conditions to the swap:<br>
1) entire columns must be swapped (not just particular elements).<br>
2) each column must be swapped at least once.<br>
3) a column cannot be swapped with itself.<p>
Here is the algorithm I am using:<br>
1) fisher-yates an array of size equal to the number of columns.<br>
2) in an outer loop, interate over each row in the array.<br>
3) in an inner loop, use the two halves of the fisher-yated ( is that even a word? ) to determine the elements to swap. That is, if the fisher-yated array looks like <c>[3,5,4,6,2,1]</c>, then effectively, col 3 and col 6 are swapped, col 5 and col 2 are swapped, and col 4 and col 1 are swapped.
<p>
What I do not like about what I have is the element-by-element swapping in the inner loop. I am concerned about the efficiency of the algorithm and whether there is a more efficient way to accomplish what I need.<p>
code using a simple 12x12 matrix as an example:<p>
<c>
#!/usr/bin/perl
my @cols = qw/0 1 2 3 4 5 6 7 8 9 10 11/;
fys( \@cols );
my @nums = ( [qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
[qw/01 02 03 04 05 06 07 08 09 10 11 12/],
);
for( my $i = 0; $i < 12; $i++) {
for( my $j = 0; $j < 6; $j++) {
($nums[$i][ $cols[$j] ], $nums[$i][ $cols[$j+6] ]) = ($nums[$i][ $cols[$j+6] ], $nums[$i][ $cols[$j] ]);
}
}
&printit;
sub printit() {
for( my $i = 0; $i < 12; $i++) {
print "@{ $nums[$i] } ";
print "\n";
}
}
sub fys {
my $arr = shift;
my $i;
for( $i = @{ $arr }; $i--;) {
my $j = int rand ($i + 1);
next if $i == $j;
@$arr[$i,$j] = @$arr[$j,$i];
}
}
</c>
output:<p>
<c>
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
03 04 01 02 11 08 09 06 07 12 05 10
</c>
As always, thank you for your input,<p>
davidj