首页 > 解决方案 > 在 C# 中等效于 Haskell 的 Data.List.Span

问题描述

您好,是否已经实施了任何有效的方法来获得 Haskell 的功能Data.List.span

span :: (a -> Bool) -> [a] -> ([a], [a])

基本上给定 alist和 apredicate我想在第一次出现错误谓词后将列表分成两pivot部分。测试元素之后的元素False可能会或可能不会尊重谓词,但我不在乎。

List: [1,2,3,1,2,3]
Predicate: x<3
Span:  `span  (x<3) [1,2,3,1,2,3]`   =>  `([1,2],[3,1,2,3])`

更新 我不关心第一个错误谓词之后的元素。我只想在第一次出现False谓词时拆分列表。序列可以True在第一个False谓词之后,但我仍然想拆分它。

标签: c#linqhaskell

解决方案


您可以使用TakeWhileand Skip

public static IEnumerable<IEnumerable<T>> SplitWhen<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
    var first = enumerable.TakeWhile(predicate);
    yield return first;
    var second = enumerable.Skip(first.Count());
    yield return second;
}

更新

为了避免多次迭代,并且不需要使用列表或数组:

public static IEnumerable<IEnumerable<T>> SplitWhen<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
    yield return enumerable.TakeWhile(predicate);
    yield return enumerable.TakeAfter(predicate);
}

public static IEnumerable<T> TakeAfter<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
    bool yielding = false;
    foreach (T item in enumerable)
    {
        if (yielding = yielding || !predicate(item))
        {
            yield return item;
        }
    }
}

推荐阅读