Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 查找特定的可枚举运算符序列:TakeWhile(!)&x2B;康卡特单曲_C#_Linq - Fatal编程技术网

C# 查找特定的可枚举运算符序列:TakeWhile(!)&x2B;康卡特单曲

C# 查找特定的可枚举运算符序列:TakeWhile(!)&x2B;康卡特单曲,c#,linq,C#,Linq,给定一个可枚举项,我想获取()所有元素,包括一个终止符(如果找不到终止符,则引发异常)。比如: list.TakeWhile(v => !condition(v)).Concat(list.Single(condition)) 除了不烂。只想走一次 对于.NET 4和Rx中的当前运营商,这是简单可行的,还是我需要编写一个新的运营商 写操作符比写这个问题花费的时间要少(虽然我认为有一半的时间是计算这个函数的名称),但我不想重复已经存在的东西 更新 好的,接线员来了。我知道,非常令人兴奋。不

给定一个可枚举项,我想获取()所有元素,包括一个终止符(如果找不到终止符,则引发异常)。比如:

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");
    }
public static IEnumerable TakeThroughTerminator([NotNull]this IEnumerable@this,funct-isterminatorester)
{
foreach(@this中的变量项)
{
收益回报项目;
如果(项目)
{
屈服断裂;
}
}
抛出新的InvalidOperationException(“列表中未找到终止符”);
}

如果您不想编写自己的运算符,这里有一些核心代码:

var input = Enumerable.Range(1, 10);

var condition = new Func<int, bool>(i => i < 5);

bool terminatorPassed = false;
var condition2 = new Func<int, bool>(i =>
        {
            try { return !terminatorPassed; }
            finally { terminatorPassed = !condition(i); }
        });

var result = input.TakeWhile(condition2).ToArray();
if (!terminatorPassed) throw new FutureException("John Connor survived");
var输入=可枚举范围(1,10);
var条件=新函数(i=>i<5);
bool terminatorPassed=假;
变量条件2=新函数(i=>
{
尝试{return!terminatorPassed;}
最后{terminatorPassed=!条件(i);}
});
var result=input.TakeWhile(条件2.ToArray();
如果(!terminatorPassed)抛出新的未来例外(“约翰·康纳幸存”);

没有一个内置程序可以有效地执行这样的操作。人们通常不需要得到满足条件的物品,而需要得到一个不满足条件的物品。你得自己写

然而,您可以使用现有的方法来构建它,但它不会那么有效,因为您需要以某种方式保持状态,这只会使代码复杂化。我不会宽恕这种质疑,因为它违背了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");
var list=Enumerable.Range(0,10);
Func条件=i=>i!=5.
int=1;
var query=list.Where(item=>condition(item)
?需要>0
:需要-->0)
.ToList();//这可能会引起问题
如果(需要!=0)
抛出新的InvalidOperationException(“序列未正确终止”);
然而,这有它自己的问题,不能真正很好地解决。正确的处理方法是手工编写代码(不使用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;
}
公共静态IEnumerable TakeWhileSingleTerminated(
这是一个数不清的来源,
Func谓词)
{
var hasTerminator=假;
var终止符=默认值(TSource);
foreach(源中的var项)
{
如果(!hasfiled)
{
if(谓语(项))
收益回报项目;
其他的
{
hasTerminator=true;
终止符=项目;
}
}
如果(!谓词(项))
抛出新的InvalidOperationException(“序列包含多个终止符”);
}
如果(!hasTerminator)
抛出新的InvalidOperationException(“序列未终止”);
屈服返回终止器;
}

仔细考虑之后,我会说,很难获得原始查询的最有效实现,因为它有相互冲突的需求。您正在混合
TakeWhile()
Single()
这两种方法,前者不能提前终止。复制最终结果是可能的(正如我们在这里都尝试过的那样),但是如果不对代码进行非平凡的更改,行为就无法实现。如果目标是只获取第一个失败的项,那么这将是完全可能的和可复制的,但是因为它不是,所以您只需要处理这个查询所遇到的问题

p、 在美国,我认为很明显,仅凭我对这个答案所做的编辑就可以看出这是多么不平凡。希望这是我最后一次编辑

int? j = null;
var result = list.TakeWhile((o, i) =>
                        {
                          if (j == null && cond(o)) { j = i + 1; }
                          return (j ?? -1) != i;
                        });
if (j == null) { throw new InvalidOperationException(); }
我会选择接线员,但怎么能确定真的没有内置的方式呢?;-)


更新1:好的,我的代码没用。我敢打赌它总是抛出一个异常,如果在检查异常之前没有执行枚举…

我只想编写一个操作符来完成这项工作…我同意-您可能可以使用一个聪明的
Zip()
进行前瞻,但这仍然会遍历枚举两次-操作符是可行的方法。顺便说一句,您对这样一个事实有何看法,即在我们知道是否允许使用这些项目(即,未引发异常)之前,很多项目就已经被生成了?好吧,我想在大多数情况下,即使使用流枚举,这仍然是最好的。同样,如果它是流式的,在没有确认成功选择之前,您无法真正对项目进行操作。有些不令人满意。一个完全安全的解决方案总是要先检查成功与否,然后再放弃。(从“从某个源进行昂贵的检索”的意义上来说,流式处理)如果没有找到终止符,则很难抛出异常。不要认为清单真的总是一张清单。看我的answer@skarmats:只要“列表”是一个
IEnumerable
,它的实际类型就与此无关。最初,我进行此查询的主要目标是尽可能提高效率,并尽快终止查询。现在我明白了这是不可能的,并且必须至少检查整个集合一次。@Jeff M:我对列表的含糊不清是因为我认为可以对列表进行比较。数一数,看看是否需要抛出异常。沿着“未找到终止符”&&“计数”