Ziggy pointed me towards a kata for today, by Norman Walsh. He wants to count the permutations of the middle letters in "morning".
I decided to use a module by Tom Phoenix:
use List::Permutor; my $p = List::Permutor->new( split //, 'ornin' ); while( my @s = $p->next ) { $hash{ join '', 'm', @s, 'g' }++; } $, = "\n"; print keys %hash;
sub cycle {
my @chars = @_;
my @result;
## Simple case -- only one choice
return $chars[0] if (@chars == 1);
for (1..@chars) {
my $char = shift(@chars);
push @result, "$char$_" for (cycle(@chars));
push(@chars, $char);
}
return @result;
}
my %words;
$words{"m${_}g"}++ for cycle(qw(o r n i n));
print "$_\n" for sort keys %words;
Note that the multiplications and divisions in this code is arranged so that to as much an extent as possible (almost) the divisions are used to keep the running value of $count as small as possible but still an integer. Keeping it small reduces the chance that it will overflow the size of the largest integer that can be exactly represented; keeping it integer avoids floating point inaccuracy from rounding errors.sub count_mid_perms {
my @letters = split//, $_[0];
pop @letters;
shift @letters;
return count_perms \@letters;
}
sub count_perms {
my $count = 1;
my $index = 0;
my %freq;
foreach my $letter (@_) {
$count *= ++$index;
$count/= ++$freq{$letter};
}
return $count;
}