<?xml version="1.0" encoding="windows-1252"?>
<node id="371228" title="Iterating over combinations" created="2004-07-01 16:11:33" updated="2005-08-11 19:28:12">
<type id="1980">
snippet</type>
<author id="137386">
blokhead</author>
<data>
<field name="doctext">
</field>
<field name="snippetdesc">
&lt;b&gt;Semantic nitpicking:&lt;/b&gt;
&lt;ul&gt;

&lt;li&gt; A &lt;i&gt;permutation&lt;/i&gt; of a set is a rearrangement of its items, using all the items, where order is important.

&lt;li&gt; The &lt;i&gt;power set&lt;/i&gt; of a set is all of its possible subsets (order is not important within subsets).

&lt;li&gt; A &lt;i&gt;combination&lt;/i&gt; "N choose K" is the number of ways to choose K things from N things (where the order of the K things doesn't matter). Often, math textbooks extend this notation to "S choose K", where S is a set instead of a number, to mean the set of all K-sized-subsets of S. In short, &lt;i&gt;combinations are when we specify the size of the subsets taken.&lt;/i&gt;

&lt;/ul&gt;

[id://128293] is a canonical way to iterate over a set's power set. It won't get you combinations in the above sense (a better name would be (tye)Re: Finding all Subsets). [id://29374] is a canonical way to iterate over permutations.

&lt;p&gt;

Here are some ways to iterate over &lt;code&gt;@S&lt;/code&gt; choose &lt;code&gt;$K&lt;/code&gt;, all the &lt;code&gt;$K&lt;/code&gt;-sized subsets of &lt;code&gt;@S&lt;/code&gt;.

&lt;code&gt;
## Filtering tye's "combinations" (power set) iterator:
my $iter = combinations(@S);
while ( my @c = $iter-&gt;() ) {
    next unless @c == $K;
    ...
}
&lt;/code&gt;

&lt;code&gt;
## Using tye's Algorithm::Loops:
NestedLoops(
    [ 0 .. $#S ],
    ( sub { [$_+1 .. $#S] } ) x ($K - 1),
    sub { my @c = @S[@_]; ... }
}
&lt;/code&gt;

Finally, the code below which uses a similar principle as [id://128293], keeping track of a list of indices. The subsets are returned in the same order as a nested for-loop.

&lt;p&gt;

&lt;b&gt;Update:&lt;/b&gt; see [id://459702] for a verbose explanation of what this code does.</field>
<field name="snippetcode">
&lt;CODE&gt;
sub combinations {
    my ($num, $arr) = @_;

    return sub { return }
        if $num == 0 or $num &gt; @$arr;

    my @pick;

    return sub {
        return @$arr[ @pick = ( 0 .. $num - 1 ) ]
            unless @pick;
        
        my $i = $#pick;
        $i-- until $i &lt; 0 or $pick[$i]++ &lt; @$arr - $num + $i;
        return if $i &lt; 0;

        @pick[$i .. $#pick] = $pick[$i] .. $#$arr;
        
        return @$arr[@pick];
    };
}
&lt;/code&gt;

You use it like this:

&lt;code&gt;
my $iter = combinations( 3 =&gt; ['a' .. 'f'] );

while ( my @c = $iter-&gt;() ) {
    print "@c\n";
}
&lt;/CODE&gt;

</field>
</data>
</node>
