我正在尝试学习 LINQ,似乎找到一系列与谓词匹配的“n”个元素应该是可能的,但我似乎无法弄清楚如何解决这个问题。
我的解决方案实际上需要第二个不同的谓词来测试序列的“结尾”,但要找到第一个未通过测试的元素,在至少 5 个元素通过 通过测试也很有趣。
这是我天真的非 LINQ 方法....
int numPassed = 0;
for (int i = 0; i < array.Count - 1; i++ )
{
if (FirstTest(array[i]))
{
numPassed++;
}
else
{
numPassed = 0;
}
if ((numPassed > 5) && SecondTest(array[i + 1]))
{
foundindex = i;
break;
}
}
最佳答案
高性能的 LINQ 解决方案是可能的,但坦率地说非常难看。这个想法是隔离与描述匹配的子序列(一系列 N 项匹配一个谓词,当找到一个与第二个谓词匹配的项时结束),然后选择其中第一个具有最小长度的子序列。
假设参数是:
var data = new[] { 0, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2 };
Func<int, bool> acceptPredicate = i => i != 0;
// The reverse of acceptPredicate, but could be otherwise
Func<int, bool> rejectPredicate = i => i == 0;
GroupBy
和一堆丑陋的有状态代码可以隔 ionic 序列(这是固有的尴尬——你必须保持非平凡的状态)。这个想法是通过一个人为的和任意的“组号”进行分组,每当我们从一个可能可以接受的子序列移动到一个绝对不能接受的子序列时选择一个不同的数字,当相反的情况发生时:
var acceptMode = false;
var groupCount = 0;
var groups = data.GroupBy(i => {
if (acceptMode && rejectPredicate(i)) {
acceptMode = false;
++groupCount;
}
else if (!acceptMode && acceptPredicate(i)) {
acceptMode = true;
++groupCount;
}
return groupCount;
});
最后一步(找到可接受长度的第一组)很容易,但还有最后一个陷阱:确保您没有选择那些不满足规定的组条件:
var result = groups.Where(g => !rejectPredicate(g.First()))
.FirstOrDefault(g => g.Count() >= 5);
以上所有内容都是通过一次遍历源序列实现的。
请注意,此代码将接受也结束源序列的项目序列(即,它不会因为我们找到满足 rejectPredicate
的项目而终止,而是因为我们用完了数据)。如果您不想这样做,则需要稍作修改。
关于c# - 如何使用 LINQ 在一行中查找与一个谓词匹配但第六个元素不匹配的 5 个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11791691/