以下は2つのバージョンです。1つはAS3用、2つ目はAS2用です。これは少し異なるアルゴリズムです(これはあなたが持っているものよりも少し効率が悪いですが、実例としてはうまくいくと思います)。これは基本的に同じアルゴリズムの複雑さであるため、問題ありません。冗長性は中間結果(短い配列)を生成することであり、後で破棄されます(ただし、これが気になる場合は、これらの配列を再利用するように変更できます)。
AS3
private function permuteRecursively(input:Array,
hash:Object = null):Array
{
var first:String;
var oldResult:Array;
var newResult:Array;
var times:int;
var current:Array;
var test:String;
if (input.length > 1)
{
first = input.shift();
if (!hash) hash = { };
oldResult = this.permuteRecursively(input, hash);
newResult = [];
for each (var result:Array in oldResult)
{
times = result.length;
while (times >= 0)
{
current = result.concat();
if (times == result.length) current.push(first);
else current.splice(times, 0, first);
test = current.join("");
if (!(test in hash))
{
newResult.push(current);
hash[test] = 1;
}
times--;
}
}
}
else newResult = [input];
return newResult;
}
AS2:
private function permuteRecursively(input:Array,
hash:Object):Array
{
var first:String;
var oldResult:Array;
var newResult:Array;
var times:Number;
var current:Array;
var test:String;
var result:Array;
if (input.length > 1)
{
first = input.shift();
if (!hash) hash = { };
oldResult = this.permuteRecursively(input, hash);
newResult = [];
for (var i:Number = 0; i < oldResult.length; i++)
{
result = oldResult[i];
times = result.length;
while (times >= 0)
{
current = result.concat();
if (times == result.length) current.push(first);
else current.splice(times, 0, first);
test = current.join("");
if (!(test in hash))
{
newResult.push(current);
hash[test] = 1;
}
times--;
}
}
}
else newResult = [input];
return newResult;
}
編集:
実は今考えてみると、どんな重複を避けようとしていたのかわかりません。上記のコードは、AACやACAなどのAACの順列を別個のものとして扱いますが(Aが「複製」されている場合でも)、AACとAACは同じと見なされます(最初のAと2番目のAが来る場合でも)元の配列のさまざまなソースから)。
生成された配列の重複した要素を削除したい場合は、明らかに、最初にソースからそれらを削除するのが最善の戦略です。