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 }