我正在尝试自动化嵌套的foreach,只要有一个主列表保存字符串列表作为以下场景的项目。
例如,我有5个主列表lstMaster
所持有的字符串列表 List<string> lst1 = new List<string> { "1", "2" };
List<string> lst2 = new List<string> { "-" };
List<string> lst3 = new List<string> { "Jan", "Feb" };
List<string> lst4 = new List<string> { "-" };
List<string> lst5 = new List<string> { "2014", "2015" };
List<List<string>> lstMaster = new List<List<string>> { lst1, lst2, lst3, lst4, lst5 };
List<string> lstRes = new List<string>();
foreach (var item1 in lst1)
{
foreach (var item2 in lst2)
{
foreach (var item3 in lst3)
{
foreach (var item4 in lst4)
{
foreach (var item5 in lst5)
{
lstRes.Add(item1 + item2 + item3 + item4 + item5);
}
}
}
}
}
我想自动化下面的for循环,无论主列表持有的列表项数目是多少?lstMaster
答案 0 :(得分:5)
只需对每个连续列表进行交叉连接:
IEnumerable<string> lstRes = new List<string> {null};
foreach(var list in lstMaster)
{
// cross join the current result with each member of the next list
lstRes = lstRes.SelectMany(o => list.Select(s => o + s));
}
结果:
List<String> (8 items)
------------------------
1-Jan-2014
1-Jan-2015
1-Feb-2014
1-Feb-2015
2-Jan-2014
2-Jan-2015
2-Feb-2014
2-Feb-2015
注意:
将
lstRes
声明为IEnumerable<string>
可防止不必要地创建将被丢弃的其他列表 每次迭代使用了本能
null
,以便第一个交叉联接可以构建一些内容(使用字符串,null + s = s
)
答案 1 :(得分:2)
要使这个真正动态,你需要两个int
循环变量数组(索引和计数):
int numLoops = lstMaster.Count;
int[] loopIndex = new int[numLoops];
int[] loopCnt = new int[numLoops];
然后你需要逻辑来遍历所有这些loopIndexes。
初始化值(可选)
for(int i = 0; i < numLoops; i++) loopIndex[i] = 0;
for(int i = 0; i < numLoops; i++) loopCnt[i] = lstMaster[i].Count;
最后一个适用于所有组合的大循环。
bool finished = false;
while(!finished)
{
// access current element
string line = "";
for(int i = 0; i < numLoops; i++)
{
line += lstMaster[i][loopIndex[i]];
}
llstRes.Add(line);
int n = numLoops-1;
for(;;)
{
// increment innermost loop
loopIndex[n]++;
// if at Cnt: reset, increment outer loop
if(loopIndex[n] < loopCnt[n]) break;
loopIndex[n] = 0;
n--;
if(n < 0)
{
finished=true;
break;
}
}
}
答案 2 :(得分:0)
var totalCombinations = 1;
foreach (var l in lstMaster)
{
totalCombinations *= l.Count == 0 ? 1 : l.Count;
}
var res = new string[totalCombinations];
for (int i = 0; i < lstMaster.Count; ++i)
{
var numOfEntries = totalCombinations / lstMaster[i].Count;
for (int j = 0; j < lstMaster[i].Count; ++j)
{
for (int k = numOfEntries * j; k < numOfEntries * (j + 1); ++k)
{
if (res[k] == null)
{
res[k] = lstMaster[i][j];
}
else
{
res[k] += lstMaster[i][j];
}
}
}
}
算法从计算所有子列表所需的组合数开始。
当我们知道我们创建一个具有恰好这个条目数的结果数组时。然后,算法遍历所有子列表,从子列表中提取项目并计算项目在结果中应出现的次数,并将项目指定的次数添加到结果中。移动到同一列表中的下一个项目并添加到剩余字段(如果列表中有两个以上的项目,则添加到所需的数量)。它会继续遍历所有子列表和所有项目。
虽然需要改进的一个方面是列表为空时。 DivideByZeroException存在风险。我没有添加。我更愿意专注于传达计算背后的想法,并且不想通过额外的检查来混淆它。
答案 3 :(得分:0)
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<IEnumerable<T>> lists)
{
IEnumerable<IEnumerable<T>> result = new List<IEnumerable<T>> { new List<T>() };
return lists.Aggregate(result, (current, list) => current.SelectMany(o => list.Select(s => o.Union(new[] { s }))));
}