C#:SkipLast 实现

标签 c# extension-methods ienumerable implementation

我需要一种方法来为我提供序列中除最后一项以外的所有项。这是我当前的实现:

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
    {
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if(iterator.MoveNext())
                while(true)
                {
                    var current = iterator.Current;
                    if(!iterator.MoveNext())
                        yield break;
                    yield return current;
                }
        }
    }

我需要它来处理除最后一项之外的所有项目。在我的例子中,我有一系列具有各种属性的对象。然后我按日期订购它们,然后我需要对除了最近的项目(这将是订购后的最后一个)之外的所有项目进行调整。

事情是,我对这些枚举器和东西还不太感兴趣,也没有人在这里问 :p 我想知道这是一个好的实现,还是我做了一个小或大的某处失误。或者如果这个问题的处理方式很奇怪,等等。

我想更通用的实现可能是 AllExceptMaxBy 方法。因为这就是它的样子。 MoreLinq有一个 MaxByMinBy 方法,我的方法有点需要做同样的事情,但返回除最大或最小项之外的所有项目。

最佳答案

这很棘手,因为“最后一个元素”不是马尔可夫停止点:在您尝试获取下一个元素之前,您无法判断您已经到达最后一个元素。这是可行的,但前提是您不介意永远成为“落后的一个元素”。这基本上就是您当前的实现所做的,它看起来还不错,尽管我可能会写得略有不同。

另一种方法是使用 foreach,除非您处于第一次迭代,否则始终生成先前返回的值:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    T previous = default(T);
    bool first = true;
    foreach (T element in source)
    {
        if (!first)
        {
            yield return previous;
        }
        previous = element;
        first = false;
    }
}

另一种选择,更接近您的代码:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if(!iterator.MoveNext())
        {
            yield break;
        }
        T previous = iterator.Current;
        while (iterator.MoveNext())
        {
            yield return previous;
            previous = iterator.Current;
        }
    }
}

这避免了相当深的嵌套(如果序列为空则提前退出)并且它使用“真实的”while 条件而不是 while(true)

关于C#:SkipLast 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/969091/

相关文章:

c# - 使用数组字段而不是大量对象

c# - 使用 lambda 获取扩展方法的第一个参数的属性? (x => x.请)

c++ - 将 “Extension methods support” 添加到 C++ 的错误指针分配技巧将来会成为问题吗?

c# - string.ElementAt() 是 O(1) 吗?

C#:是否可以返回 IOrderedEnumerable<T>?

c# - 如何将 xml 片段解析为节点并将它们附加到具有指定默认 namespace 的节点,以便它们成为该 namespace 的一部分?

c# - 如何将绑定(bind)添加到数据网格中的列?

c# - asp.net 如何在下拉菜单中添加复选框

kotlin - 调用接口(interface)中声明的接收器函数

c# - 聚合 IEnumerable 中的一系列连续 block