I've been tinkering with combinations of strings from different arrays, and discovered that the ubiquitous
glob solution breaks for long input strings.
Update: The below example is for Strawberry Perl 5.16.1 on Windows. On Ubuntu 10.4, Perl 5.10.1 (i486-linux-gnu-thread-multi), it first breaks at 4027.
Here's a trivial example to show the effect:
#!/usr/env/perl
use strict;
use warnings;
my $q = (shift or 129);
my @x = ( 'A' x $q, 'B' x $q );
my $glob = '{' . join(',', @x) . '}';
while (my $g = glob($glob)) {
print "$g\n"; # no output if $q > 129
}
##### returns nothing with 129 ####
What I really want to do is more like this, but glob also fails when longer strings are used:
my @x = (1..10);
my @y = qw(one two three four five six seven eight nine ten);
my @z = qw(Amy Bob Cal Deb Eck Fay Gin Hob Ian Jan);
my @xyz = (\@x, \@y, \@z);
my $glob = join( ',', map { '{' . join( ',', @$_ ) . '}' } @xyz );
Q1: Why does glob quietly fail?
Q2: Is there a built-in, core, or module that is not so limited?
Instead of that, I suspect I'll have to do something like the following. This is very simplistic, but does the job. (I'm sure this has been done before, but I haven't spent enough time searching.)
Q3: Any comments here?
sub make_combo_iter
{
my $array_ref = shift;
# last index of top level
my $size = scalar( @{$array_ref} );
# create array of last indices
my @array_limits;
for my $i (0..$size-1)
{
$array_limits[$i] = scalar( @{$array_ref->[$i]} ) - 1;
}
# one counter for each sub-array
my @array_counter = (0) x $size;
my $done = 0;
my $iter = sub {
if ($done)
{
$done = 0;
return undef;
}
my @next_combo;
# compute @next_combo
for my $i (0..$size-1)
{
push @next_combo, $array_ref->[$i][$array_counter[$i]];
}
# increment counters, set $done if the last one rolls over
my $rollover = 0;
for my $c (0..$size-1)
{
if (++$array_counter[$c] > $array_limits[$c])
{
$array_counter[$c] = 0; # reset
$rollover = 1; # carry
}
else
{
$rollover = 0; # no carry
last; # no more increments
}
}
# if the last array rolled over, set the done flag
if ( $rollover )
{
$done = 1;
}
return \@next_combo;
}; # anonymous iterator sub
return $iter;
} # make_combo_iter
-QM
--
Quantum Mechanics: The dreams stuff is made of