我希望找到所有已排序的字符串组合,仅包括具有特定字符串的字符串,给定以下结构:
//elements
string[] a = { "a1" };
string[] b = { "b1", "b2", "b3" };
string[] c = { "c1", "c2" };
//element groups
string[][] m = { a, b };
string[][] n = { a, b, c };
string[][] o = { b };
string[][] p = { b, c };
//element group groupings
string[][][] groupGroupings = { m, n, o, p };
给定groupGroupings,并过滤为仅包含组合,其中,假设“b2”存在,输出应为以下内容:
["a1", "b2"]
["a1", "b2", "c1"]
["a1", "b2", "c2"]
["b2"]
["b2", "c1"]
["b2", "c2"]
我有一个有效的递归方法,但它有点难看,我不禁觉得有更优雅的方法。
我对如何使用LINQ完成这样的事情感兴趣,不确定是否可行,但我还没有看到它。
我目前的做法:
List<IEnumerable<IEnumerable<string>>> all = new List<IEnumerable<IEnumerable<string>>>();
foreach (var groups in groupGroupings)
{
var combos = FindAllCombinations(groups).Where(i => i.Any(g => g.Contains("b2"))).ToList();
all.Add(combos);
}
private static IEnumerable<IEnumerable<string>> FindAllCombinations(string[][] groups)
{
if (groups.Length > 0)
{
var group = groups.First();
var remainingGroups = groups.SkipWhile(g => !g.Equals(group)).Skip(1);
var remainingCombinations = FindAllCombinations(remainingGroups.ToArray()).ToList();
foreach (var element in group)
{
if (remainingGroups.Count() > 0)
{
foreach (var c in remainingCombinations)
{
List<string> combo = new List<string>() { element };
combo.AddRange(c);
yield return combo;
}
}
else
yield return new List<string>() { element };
}
}
}
答案 0 :(得分:1)
我不确定你为什么不喜欢递归解决方案。我认为这是一个很好的。但是,我认为可以做一些改进。
创建ToArray()
变量时调用remainingGroups
。否则,将使用IEnumerable<T>
/ SkipWhile
定义Skip
,并且每次调用.Count()
时,都必须一次又一次地对其进行评估,并且将枚举整个集合。使用数组,您可以使用Length
代替。
我不明白你为什么要使用SkipWhile
。 group
始终是第一个元素,因此SkipWhile(g => !g.Equals(group))
永远不会跳过任何内容。我想您可以使用Skip(1)
并省略SkipWhile
。
您可以在外部elementList = new List<string>() { element }
循环的最开始定义foreach
,并使用yield return
/ {{1将其用于内部循环中的Concat()
值方法链。
ToList()
您还可以将private static IEnumerable<IEnumerable<string>> FindAllCombinations(string[][] groups)
{
if (groups.Length == 0)
yield break;
var group = groups.First();
var remainingGroups = groups.Skip(1).ToArray();
var remainingCombinations = FindAllCombinations(remainingGroups).ToList();
foreach (var element in group)
{
var elementList = new List<string>() { element };
if (remainingGroups.Length > 0)
{
foreach (var c in remainingCombinations)
{
yield return elementList.Concat(c).ToList();
}
}
else
yield return elementList;
}
}
更改为foreach
方法:
Select
<强>更新强>
如果您真的想使用LINQ,可以使用Eric Lippert在他的博客上描述的笛卡尔积法:Computing a Cartesian Product with LINQ
var all = groupGroupings.Select(g => FindAllCombinations(g).Where(i => i.Any(j => j.Contains("b2"))).ToList()).ToList();