sub combinations { my @list= @_; # List of items to choose from my @pick= (0) x @list; # Whether we want each item # $pick[$i] means include $list[$i] in results. # So @pick currently describes the empty subset. # Return a closure that, each time it is called, returns # the next subset: return sub { # Treat @pick as a base-2 number and increment it. # Note that @pick started as all 0s and we stop # after it is all 1s so all cases get covered. # (See original node for handling the empty subset) # Start at least-significant bit, $pick[0]: my $i= 0; # Increment a bit. If the bit was already 1, then # set it to 0 and continue to next bit: while( 1 < ++$pick[$i] ) { $pick[$i]= 0; # If we've run out of bits, then we were at # all 1s and so are done. Return empty list: return if $#pick < ++$i; } # The grep() below returns the indices for which # $pick[$_] is not 0. The @list[...] is an array # slice that returns the list of elements of @list # at the indices returned by grep. That is, we # return all items $list[$i] where $pick[$i] is # not 0. Same as: # map { $pick[$_] ? $list[$_] : () } 0..$#list; return @list[ grep $pick[$_], 0..$#pick ]; }; } my $next= combinations( 50..59 ); my @comb; while( @comb= $next->() ) { # do work with @comb here }