This isn't necessarily the most efficient, but here's how you could do this using non-recursive methods returning IEnumerable<T>
. Something like this will probably require the least possible memory, since it doesn't require building all the permutations in memory. Instead, it just allows you to iterate over the permutations one by one.
private static void Main()
{
var input1 = new[] {"1", "2", "3"};
foreach (var output in EnumeratePermutations(input1))
Debug.WriteLine(String.Join(",", output));
}
private static IEnumerable<T[]> EnumeratePermutations<T>(T[] input)
{
return from partCount in Enumerable.Range(1, input.Length)
let inputs = Enumerable.Repeat(input, partCount).ToArray()
from indices in EnumerateCrossjoinIndices(inputs)
where indices.Distinct().Count() == indices.Length
select indices.Select(n => input[n]).ToArray();
}
private static IEnumerable<int[]> EnumerateCrossjoinIndices(params Array[] arrays)
{
var arrayCount = arrays.Length;
if (arrayCount == 0)
yield break;
if (arrays.Any(a => a.Length == 0))
yield break;
var indexer = new int[arrayCount];
yield return (int[]) indexer.Clone();
for (var dimension = arrayCount - 1; dimension >= 0; --dimension)
{
++indexer[dimension];
if (indexer[dimension] == arrays[dimension].Length)
indexer[dimension] = 0;
else
{
yield return (int[]) indexer.Clone();
dimension = arrayCount;
}
}
}
EnumerateCrossjoinIndices
takes n arrays of potentially different lengths and yields an enumeration of the indices that would be used in a crossjoin operation. For example, given {"1","2"}
and {"A","B","C"}
, it would yield 6 arrays {0,0}
, {0,1}
, {0,2}
, {1,0}
, {1,1}
, {1,2}
. Note that the arrays yielded by this method contain indices into the input arrays, not the elements at those indices.
EnumeratePermutations
takes an array and yields the permutations of the items of that array. It does this by enumerating over the indices that would be used to crossjoin the array against itself x times (where x = 1 to n, where n is the number of items in the array). It then filters out any set of crossjoin indices where the set isn't a distinct set.