How to get all possible combinations for n arrays with different number of elements? How to get all possible combinations for n arrays with different number of elements? arrays arrays

How to get all possible combinations for n arrays with different number of elements?


This works:

Func<    IEnumerable<IEnumerable<int>>,    IEnumerable<IEnumerable<int>>> f0 = null;f0 = xss =>{    if (!xss.Any())    {        return new [] { Enumerable.Empty<int>() };    }    else    {        var query =            from x in xss.First()            from y in f0(xss.Skip(1))            select new [] { x }.Concat(y);        return query;    }};Func<IEnumerable<IEnumerable<int>>, IEnumerable<string>> f =    xss => f0(xss).Select(xs => String.Join(",", xs));

So if I have this input:

var input = new []{    new [] { 1, 2, 3, 4, },    new [] { 6, 7, 5, 2, 1, },    new [] { 22, 4, 6, 8, 4, 8, 5, 4, },};

I can get the results this way:

var results = f(input);

results


Here's a version which simply sums the results, as per the request in the comments:

Func<IEnumerable<IEnumerable<int>>, IEnumerable<int>> f = null;f = xss =>{    if (!xss.Any())    {        return new [] { 0 };    }    else    {        var query =            from x in xss.First()            from y in f(xss.Skip(1))            select x + y;        return query;    }};var input = new []{    new [] { 1, 2, 3, 4, },    new [] { 6, 7, 5, 2, 1, },    new [] { 22, 4, 6, 8, 4, 8, 5, 4, },};var results = f(input);


I think the linq version looks awesome:

from i in afrom j in bfrom k in cfrom m in dselect String.Join(",", i, j, k, m)

But the answer to your question is not easy.Eric Lippert wrote about it on his blog:

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx


The following extension method imitates a nested stack of foreach loops:

public static class Ext{    public static void ForEachNested<T>(        this IEnumerable<IEnumerable<T>> sources,        Action<IEnumerable<T>> action)    {        var enumerables = sources.ToArray();        Stack<IEnumerator<T>> fe = new Stack<IEnumerator<T>>();        fe.Push(enumerables[0].GetEnumerator());        while (fe.Count > 0)        {            if (fe.Peek().MoveNext())            {                if (fe.Count == enumerables.Length)                    action(new Stack<T>(fe.Select(e => e.Current)));                else                    fe.Push(enumerables[fe.Count].GetEnumerator());            }            else            {                fe.Pop().Dispose();            }        }    }}

You could use it as follows:

new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = string.Join(",", e); });

or, to do your maths,

new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = e.Sum(); });

This has the advantage of not performing hundreds of array allocations.

Ordinarily I'd shy away from using a LINQ-like method to act rather than query but as this is closely imitating how a foreach loop works I don't mind so much.