http://qs321.pair.com?node_id=467617

davidj has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks,

The following question may sound like homework, but I assure you, it is not.

I have a situation where I need to swap columnar data in a 2-dimensional array. There are 3 conditions to the swap:
1) entire columns must be swapped (not just particular elements).
2) each column must be swapped at least once.
3) a column cannot be swapped with itself.

Here is the algorithm I am using:
1) fisher-yates an array of size equal to the number of columns.
2) in an outer loop, interate over each row in the array.
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 [3,5,4,6,2,1], then effectively, col 3 and col 6 are swapped, col 5 and col 2 are swapped, and col 4 and col 1 are swapped.

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.

code using a simple 12x12 matrix as an example:

#!/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]; } }
output:

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
As always, thank you for your input,

davidj