c# - 寻找特定的可枚举运算符序列 : TakeWhile(! ) + Concat Single

标签 c# linq

给定一个 Enumerable,我想 Take() 所有元素直到并包括终止符(如果找不到终止符则抛出异常)。像这样的东西:

list.TakeWhile(v => !condition(v)).Concat(list.Single(condition))

..除了不蹩脚。只想走一遍。

对于 .NET 4 和 Rx 中的当前运算符,这是否可以简洁地实现,或者我是否需要编写一个新的运算符?

写操作符比写这个问题花费的时间更少(虽然我认为一半的时间会弄清楚如何命名这个函数),但我只是不想复制已经存在的东西。

更新

好的,这是接线员。非常令人兴奋,我知道。无论如何,可以从内置运算符构建它吗?

    public static IEnumerable<T> TakeThroughTerminator<T>([NotNull] this IEnumerable<T> @this, Func<T, bool> isTerminatorTester)
    {
        foreach (var item in @this)
        {
            yield return item;
            if (isTerminatorTester(item))
            {
                yield break;
            }
        }

        throw new InvalidOperationException("Terminator not found in list");
    }

最佳答案

没有内置函数可以有效地执行此类操作。人们通常需要获得满足条件的元素和不满足条件的元素。您必须自己编写。

但是您可以使用现有方法构建它,它不会那么有效,因为您需要以某种方式保持状态只会使您的代码复杂化。我不会容忍这种查询,因为它违背了 LINQ 的理念,我会自己编写。但是既然你问了:

var list = Enumerable.Range(0, 10);
Func<int, bool> condition = i => i != 5;
int needed = 1;
var query = list.Where(item => condition(item)
                                   ? needed > 0
                                   : needed-- > 0)
                .ToList(); // this might cause problems
if (needed != 0)
    throw new InvalidOperationException("Sequence is not properly terminated");

然而,这有其自身的问题,无法很好地解决。处理这个问题的正确方法是手动编写所有代码(不使用 LINQ)。这会给你完全相同的行为。

public static IEnumerable<TSource> TakeWhileSingleTerminated<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)
{
    var hasTerminator = false;
    var terminator = default(TSource);
    foreach (var item in source)
    {
        if (!hasFailed)
        {
            if (predicate(item))
                yield return item;
            else
            {
                hasTerminator = true;
                terminator = item;
            }
        }
        else if (!predicate(item))
            throw new InvalidOperationException("Sequence contains more than one terminator");
    }
    if (!hasTerminator)
        throw new InvalidOperationException("Sequence is not terminated");
    yield return terminator;
}

经过深思熟虑后,我会说很难最有效地实现原始查询,因为它有相互冲突的要求。您将提前终止的 TakeWhile() 与不能提前终止的 Single() 混合在一起。复制最终结果是可能的(正如我们在这里都尝试过的那样),但如果不对代码进行重大更改,行为就无法复制。如果目标是只获取第一个失败的项目,那么这将是完全可能和可复制的,但由于它不是,您将只需要处理此查询存在的问题。

p.s.,我认为仅凭我对这个答案所做的编辑就可以看出这是多么重要。希望这是我最后一次编辑。

关于c# - 寻找特定的可枚举运算符序列 : TakeWhile(! ) + Concat Single,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5479375/

相关文章:

c# - PLS-00306 : wrong number or types of arguments when calling oracle function

c# - 如何动态执行多个 Linq to Entities 排序

c# - LINQ to SQL 加入 FirstOrDefault() 问题

c# - 不支持 Linq to Entities SqlFunctions.DateDiff

c# - 组合依赖于其他可观察量的可观察量

C# MVVM 处理 UserID 并将其传递给不同的模型和 View 模型

c# - 将键值对与列表一起使用以动态创建配对值数组

c# - 当您在需要 Expression 的地方使用自定义方法时,如何创建 C# 编译错误?

c# - 实体数据源包含功能

c# - 执行位于 JavaScript 代码隐藏中的函数?