組合せ

配列の中から、任意の個数の組合せを取り出す件。
朝から、うーんうーんと唸っていて、googleさんに聞いてみたら、解決策を授けてくださいました。
http://d.hatena.ne.jp/ibaza/20080303/1204476552 より

nCr(n個からr個取り出す組合せ)は、
1. リストの先頭要素を除いた残りのリストからr-1個を選ぶ組合せのそれぞれに先頭要素を加えたものと、
2. リストの先頭要素を除いたリストからr個を選ぶ組合せ
の合計となる(1および2はそれぞれ再帰処理となる)。
3. n = r のときは選び方は一つなのでリストをそのままリストにして返す。例:(a b c) なら( (a b c) ) にして返す
4. r = 1 のときは選び方はn通りあるのでリストの要素をそれぞれリストにして返す。例:(a b c) なら ( (a) (b) (c) ) にして返す
5. r = 0 または r がリストの要素数より大きいときは空リストを返す。

ということで、perlで実装

sub comb{
    my ($r,$list) = @_;
    my $len = @$list;
    if($len == $r){ # 3の条件
        return [$list];
    }elsif($r == 1){ # 4の条件
        return [map {[$_]} @$list];
    }elsif($r == 0 or $len < $r){ # 5の条件
        return [];
    }else{
        my ($top,@rest) = @$list;
        my @a1 = map { [$top,@{$_}]} @{comb($r-1,\@rest)}; # 1の処理
        my @a2 = @{comb($r,[@rest])}; # 2の処理
        return [@a1,@a2]; # 1 と 2 を合わせたもの
    }
}

以下使い方。

my @a = (0..9);

for(my $i=0;$i<@a;$i++){
    my $res = comb($i,\@a);
    foreach(@$res){
        print join(",",@$_),"\n";
    }
};