This isn't so much a difficult thing to do, but I was writing it up as part of a homework assignment and thought it was a nice, elegant formulation. Naturally, I'm hoping that my fellow monks will be able to improve on it. :-)
sub gen_seqs { my ($n) = @_; my @seqs = (); if($n == 1) { $seqs[0] = [0]; $seqs[1] = [1]; } else { my @seqs_0 = &gen_seqs($n-1); for my $seq (@seqs_0) { unshift @$seq, 0; } my @seqs_1 = &gen_seqs($n-1); for my $seq (@seqs_1) { unshift @$seq, 1; } push @seqs, @seqs_0, @seqs_1; } return @seqs; }

Replies are listed 'Best First'.
Re: Generate all (0,1)-sequences in lexicographic order
by Abigail-II (Bishop) on Mar 09, 2003 at 23:03 UTC
    That's not very efficient. You go into recursion twice, resulting in an exponential amount of subroutine calls. For n = 10, you call gen_seqs 1024 times. The following snippet calls gen_seqs only n + 1 times, while dealing with n = 0 correctly:
    sub gen_seqs; sub gen_seqs { return [] if $_ [0] <= 0; my @s = gen_seqs $_ [0] - 1; (map {[0 => @$_]} @s), (map {[1 => @$_]} @s) }

    Abigail

Re: Generate all (0,1)-sequences in lexicographic order
by dws (Chancellor) on Mar 09, 2003 at 22:07 UTC
    Heaven help whoever call gen_seqs(0).

    Why do you need both @seqs_0 and @seqs_1? They'll both hold the same thing, and you're dealing with them destructively. Unless I'm missing something, I'd think you could do

    my @subseq = gen_seqs($n-1); unshift @$seq, 0 foreach @subseq; unshift @$seq, 1 foreach @subseq; push @seqs, @subseq, @subseq;

      Why do you need both @seqs_0 and @seqs_1? They'll both hold the same thing, and you're dealing with them destructively. Unless I'm missing something, I'd think you could do

      my @subseq = gen_seqs($n-1); unshift @$seq, 0 foreach @subseq; unshift @$seq, 1 foreach @subseq; push @seqs, @subseq, @subseq;

      Hmm? The idea is to generate two copies of the (n-1)-sequences, prepend a 0 to everything in the first copy, and prepend a 1 to everything in the second copy. Unless I'm missing something (perhaps about $seq, which you don't declare here and which I don't use except in the code that I think you're replacing), you'll stuff a 0 onto each sequence in @subseq, then a 1 onto each sequence, and throw two copies of that into @seqs. Not the same thing.

      I could easily be missing something, though. I'm in the middle of debugging some backtracking code right before a deadline, so I'm not thinking terribly clearly at the moment. :-) Thanks for taking the time to look it over.

      --
      F o x t r o t U n i f o r m
      Found a typo in this node? /msg me
      The hell with paco, vote for Erudil!

Re: Generate all (0,1)-sequences in lexicographic order
by hv (Prior) on Mar 10, 2003 at 03:44 UTC

    You build arrays of zeros and ones here, but usually I prefer strings. Here's an interesting way to build an iterator for all strings of length n, base b, given an appropriate b:

    sub iterator { my($n, $b) = @_; my $limit = $b - 1; die "base out of range" unless $limit =~ /^\d$/; my $str; sub { return $str = "0" x $n unless defined $str; return $str =~ s/([^$limit])($limit*)$/($1+1)."0" x length($2)/e ? $str : undef; } } # Usage: my $iterator = iterator(5, 2); while (defined($next = $iterator->())) { print "next: $next\n"; }

    Hugo