我有一个List<List<string>>
,代表行和列的网格(每一个的计数都是动态的)。
我需要遍历所有项目并在一个方向上显示所有可能的组合。
例如,如果我有以下项目:
var items = new List<List<string>>
{
new List<string> {"A", "B", "C", "D"},
new List<string> {"E", "F", "G", "H"},
new List<string> {"I", "J", "K", "L"},
};
输出应为:
---> *ABCD-ABCH-ABCL-ABGD-ABGH-ABGL-ABKD-ABKH-ABKL-........... IJKL*.
如何遍历列表以达到此结果?
答案 0 :(得分:1)
您想要的是转置的笛卡尔积。所以把它分解。首先让我们进行移调:
public static List<List<T>> Transpose(
this List<List<T>> sequences)
{
// TODO: throw if sequences is null
// TODO: throw if sequences contains any null
// TODO: throw if the sequences are not all the same length
return Enumerable.Range(0, sequences[0].Count)
.Select(i =>
Enumerable.Range(0, sequences.Count)
.Select(j => sequences[j][i])
.ToList())
.ToList();
}
我们可以从以下答案中提取笛卡尔积:https://stackoverflow.com/a/3098381/88656
现在您问题的答案很简单。
IEnumerable<string> combinations = items
.Transpose()
.CartesianProduct()
.Select(sequence => string.Join("", sequence));
请记住,解决这些问题的方法是将问题分解为对序列进行更基本操作的工作流程,然后将扩展方法一起组合到工作流程中 。
答案 1 :(得分:-1)
如果需要N个唯一元素的组合,则解决此问题的另一种方法是将矩阵展平:
var elementArray = items.SelectMany(x => x).ToList();
将{{'A', 'B', 'C'}, {'D', 'E', 'F'}}
变成{'A', 'B', 'C', 'D', 'E', 'F'}
然后使用来自another question的以下LINQ扩展名(将其放置在项目中的任何位置):
public static class Ex
{
public static IEnumerable<IEnumerable<T>> DifferentCombinations<T> (this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
elements.Skip(i + 1).DifferentCombinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}
用作:
var combinations = elementArray.DifferentCombinations(4)
.Select(
l => string.Join("", l.ToArray())
).ToList();
在这种情况下,它的长度最多为4(DifferentCombinations(4)
)。