【问题标题】:TakeWhile, but get the element that stopped it alsoTakeWhile,但也获取停止它的元素
【发布时间】:2012-08-09 12:28:31
【问题描述】:

我想在 LINQ to Objects 上使用 LINQ TakeWhile 函数。但是,我还需要知道“破坏”函数的第一个元素,即条件不成立的第一个元素。

是否有一个函数可以获取所有不匹配的对象以及第一个匹配的对象?

例如,给定集合{1, 2, 3, 4, 5, 6, 7, 8}

mySet.MagicTakeWhile(x => x != 5);

=> {1, 2, 3, 4, 5}

【问题讨论】:

  • 您可以轻松编写这样的方法,但这不会是“懒惰”,因为您必须知道最后一项的位置才能获得下一项。
  • This question 不是完全重复,而是共享 an answer.

标签: c# .net linq linq-to-objects


【解决方案1】:

我认为你可以使用SkipWhile,然后取第一个元素。

var elementThatBrokeIt = data.SkipWhile(x => x.SomeThing).Take(1);

更新

如果你想要一个单一的扩展方法,你可以使用以下:

public static IEnumerable<T> MagicTakeWhile<T>(this IEnumerable<T> data, Func<T, bool> predicate) {
    foreach (var item in data) {
        yield return item;
        if (!predicate(item))
            break;
    }
}

【讨论】:

  • 这需要多次调用。在那种情况下我可以做FirstOrDefault
  • @Maarten,很好的答案 - 您可以通过删除最后的 yield break; 来保存一行
  • 原答案单行不行。这不是它的工作原理。 .Take(n) 接受一个集合并返回相同的集合,但在 n 个元素之后将其封顶。在这种情况下。它将获取从 SkipWhile 返回的集合,然后从中获取 1 个元素。实际上是 FirstOrDefault。它不会“附加”集合。
  • 当元素是列表中的第一个元素时,这对我不起作用 - 我得到了前两个元素。最后改用这个:stackoverflow.com/a/3098714/1579626
【解决方案2】:

LINQ to Objects 没有这样的运算符。但是自己实现TakeUntil 扩展很简单。这是来自moreLinqone such implementation

【讨论】:

  • 不幸的是,他们没有将其包含在 MoreLinq NuGet 中。我将复制并粘贴代码。谢谢!
  • 名称TakeUntil 没有传达含义。 Take 盒子里的鸡蛋Until 你得到一个坏蛋并不意味着你拿走了那个坏蛋。
  • @bradgonesurfing TakeUntilInclusive?
  • TakeUntil 现在包含在 MoreLinq NuGet 中。这里还有一个来自 GitHub 的更新链接:github.com/morelinq/MoreLINQ/blob/master/MoreLinq/TakeUntil.cs
【解决方案3】:

只是为了好玩:

var a = new[] 
    {
        "two",
        "three",
        "four",
        "five",
    };
  Func<string, bool> predicate = item => item.StartsWith("t");      
  a.TakeWhile(predicate).Concat(new[] { a.SkipWhile(predicate).FirstOrDefault() })

【讨论】:

  • 这也需要两个函数调用。另外,您可以跳过SkipWhile,直接转到a.FirstOrDefault(predicate)
  • 值得注意的是,如果源可枚举随每个枚举发生变化,即来自 RNG 的数字流,这将不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
相关资源
最近更新 更多