我有一些在编程时未知的数组,可能是3或4或7 ......每个数组都有一些元素,即
a={1 2 3 4}
b={6 7 5 2 1}
c={22 4 6 8 4 8 5 4}
d={....}
e, f, g, ...
我希望通过从每个数组中抽取一个数字来获得所有可能的组合,例如我拿起的一个案例" 1"来自a," 7"从b,第一" 8"从c,d [3],e [5],...来制作" 1,7,8,d [3],e [5],......"。它不可能使用嵌套的for循环,因为我不知道编译时的数组数。如果它已知例如4个数组(a,b,c,d),我可以使用4个循环:
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();
}
}
}
}
但对于不同数量的阵列,我不知道。
答案 0 :(得分:8)
这有效:
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));
所以如果我有这个输入:
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);
这是一个根据评论中的请求简单总结结果的版本:
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)
我认为linq版本看起来很棒:
from i in a
from j in b
from k in c
from m in d
select String.Join(",", i, j, k, m)
但问题的答案并不容易。 Eric Lippert在他的博客上写了这篇文章:
http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
答案 2 :(得分:2)
以下扩展方法模仿foreach
循环的嵌套堆栈:
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();
}
}
}
}
您可以按如下方式使用它:
new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = string.Join(",", e); });
或者,做数学,
new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = e.Sum(); });
这样做的好处是不会执行数百个数组分配。
通常我会回避使用类似LINQ的方法来行动而不是查询,但因为这正在模仿foreach
循环工作我不太介意。