How to get all possible combinations for n arrays with different number of elements?
我有一些数组在编程时是未知的,可能是3、4或7…每个数组都有一些元素,即,
1 2 3 4 5 | a={1 2 3 4} b={6 7 5 2 1} c={22 4 6 8 4 8 5 4} d={....} e, f, g, ... |
我想通过从每个数组中抽取一个数字来获得所有可能的组合,例如,我从A中选取"1",从B中选取"7",从C、D[3],E[5]中选取"8"…使"1,7,8,d[3],e[5],…"。不能使用嵌套for循环,因为我不知道编译时数组的数量。如果知道例如4个数组(A、B、C、D),我可以使用4个循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 | for (int i = 0; i <= a.Length-1; i++) { for (int j = 0; i <= b.Length-1; j++) { for (int k = 0; i <= c.Length-1; k++) { for (int m = 0; i <= d.Length-1; m++) { Response[f++] = a[i].toString()+","+b[j].toString()+","+c[k].toString()+","+d[m].toString(); } } } } |
但是对于不同数量的数组,我不知道。
这工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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)); |
所以如果我有这个输入:
1 2 3 4 5 6 |
我可以这样得到结果:
1 | var results = f(input); |
下面是一个版本,它根据注释中的请求简单地对结果进行汇总:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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); |
以下扩展方法模拟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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(); } } } } |
您可以使用它如下:
1 |
或者,做你的数学,
1 |
这样做的好处是不执行数百个阵列分配。
通常,我会避免使用类似LINQ的方法来执行操作,而不是使用查询,但由于这是在密切地模仿
我觉得Linq版本看起来很棒:
1 2 3 4 5 | from i in a from j in b from k in c from m in d select String.Join(",", i, j, k, m) |
但你的问题的答案并不容易。埃里克·利珀特在他的博客上写到:
http://blogs.msdn.com/b/ericlippet/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx