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


In reply to glob quietly fails by QM

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.