我的列表包含{a,b,c,at,h,c,bt}
我想分成List<List<string>>{{a,b,c},{at,h,c},{bt}};
如果特定字符串包含"t"
我需要打破该行,我该如何在linq中执行此操作?
答案 0 :(得分:4)
嗯,有一种可怕的方式:
int tCounter = 0;
var groups = sequence.GroupBy(x => x.Contains("t") ? ++tCounter : tCounter)
.Select(group => group.ToList())
.ToList();
或等效(但没有调用Select):
int tCounter = 0;
var groups = sequence.GroupBy(x => x.Contains("t") ? ++tCounter : tCounter,
(count, group) => group.ToList())
.ToList();
这依赖于GroupBy
条款中的副作用 - 这是一个非常糟糕的主意。 LINQ是围绕功能理想设计的,其中查询不应具有副作用。您将副作用放在使用查询的代码中,而不是在查询本身中。这样可行,但我不建议。
这是一个简短而完整的演示,只是为了证明它确实有效:
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
static void Main(string[] args)
{
var input = new List<string>{"a","b","c","at","h","c","bt"};
int tCounter = 0;
var groups = input.GroupBy(x => x.Contains("t") ? ++tCounter : tCounter)
.Select(group => group.ToList())
.ToList();
foreach (var list in groups)
{
Console.WriteLine(string.Join(", ", list));
}
}
}
输出:
a, b, c
at, h, c
bt
我们真正需要的是“扫描”(又名foldl,我相信 - 不确定)运营商 - 如聚合,但提供正在运行的聚合。然后扫描可以跟踪当前Ts的数量以及当前值,GroupBy
可以对此进行处理。
编写这样的操作符并不难,而IIRC是Reactive Extensions System.Interactive assembly已经包含了一个。您可能想要使用它而不是我可怕的笨蛋黑客。那时你可以在LINQ中合理地写出它。
答案 1 :(得分:2)
内置的扩展方法Aggregate正是您所需要的。
var source = new List<string> { "a", "b", "c", "at", "h", "c", "bt" };
var result = source.Aggregate(new List<List<string>>(), (list, s) =>
{
if (list.Count == 0 || s.Contains('t')) list.Add(new List<string>());
list.Last().Add(s);
return list;
});
result
为List<List<string>>
。
答案 2 :(得分:1)
我不认为可以使用内置的Linq方法 (实际上,它可以......看到其他答案),但你可以很容易为此目的创建自己的扩展方法:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, Func<T, bool> isSeparator)
{
List<T> list = new List<T>();
foreach(T item in source)
{
if (isSeparator(item))
{
if (list.Count > 0)
{
yield return list;
list = new List<T>();
}
}
list.Add(item);
}
if (list.Count > 0)
{
yield return list;
}
}
使用如下:
var list = new[] { "a", "b", "c", "at", "h", "c", "bt" };
var result = list.Split(s => s.Contains("t"));
答案 3 :(得分:0)
这个问题不会让LINQ尖叫。如果你要求LINQ答案作为心理练习,那就是别的,但这就是我如何解决它(使用一个普通的循环):
List<List<string>> list = new List<List<string>>();
List<string> sublist = new List<string>();
foreach (string element in originalList)
{
if (element.Contains("t"))
{
list.Add(sublist);
sublist = new List<string>();
}
sublist.Add(element);
}
list.Add(sublist);
不要误会我的意思,我滥用LINQ比任何人都多。 :)