为什么C#中没有ReverseEnumerator?

发布于 2025-01-06 18:15:00 字数 402 浏览 0 评论 0原文

有谁知道是否有特定原因或设计决定不在 C# 中包含反向枚举器?如果有一个与 C++ reverse_iterator 等效的东西,就像 Enumerator 与 C++ iterator 等效一样,那就太好了。可以反向迭代的集合只需实现类似 IReverseEnumerable 的功能,并且可以执行以下操作:

List<int>.ReverseEnumerator ritr = collection.GetReverseEnumerator();
while(rtir.MoveNext())
{
 // do stuff
}

这样,您将能够以相同的方式迭代列表和 LinkedList,而不是对一个使用索引器,对另一个使用前一个链接,从而实现更好的抽象

Does anyone know if there was a specific reason or design decision to not include a reverse enumerator in C#? It would be so nice if there was an equivalent to the C++ reverse_iterator just like Enumerator is the equivalent of the C++ iterator. Collections that can be reverse-iterated would just implement something like IReverseEnumerable and one could do something like:

List<int>.ReverseEnumerator ritr = collection.GetReverseEnumerator();
while(rtir.MoveNext())
{
 // do stuff
}

This way, you would be able to iterate Lists and LinkedLists in the same way rather than using indexer for one and previous links for the other thus achieving better abstraction

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不醒的梦 2025-01-13 18:15:00

实现这一点是完全有可能的。就我个人而言,我几乎从不进行反向迭代。如果我需要这样做,我首先调用 .Reverse() 。也许这也是 .NET BCL 设计者的想法。

默认情况下,所有功能均未实现。它们需要被设计、实施、测试、记录和支持。 - 陈雷蒙

这就是为什么您不实现实用性不大的功能的原因。您从最重要的功能开始(例如从前到后迭代)。你会在某个地方停下来,要么你的预算已经耗尽,要么你认为没有必要继续下去。

有很多东西不在.NET 基类库中。在 .NET 4 之前,甚至还没有 File.EnumerateLines。我敢说,对于大多数人来说,这样的功能比反向迭代更重要。

您可能在逆向迭代很常见的业务领域工作。我的经历恰恰相反。作为框架设计者,您只能猜测谁将使用您的框架以及这些人将需要哪些功能。很难划清界限。

It would be entirely possible to implement this. Personally, I almost never reverse-iterate. If I need to do this, I call .Reverse() first. Probably this is what the .NET BCL designers thought as well.

All features are unimplemented by default. They need to be designed, implemented, tested, documented and supported. - Raymond Chen

And this is why you don't implement features that provide little utility. You start with the most important features (like iterating front-to-back). And you stop somewhere where either your budget is depleted or where you think is does not make sense to continue.

There are many things that are not in the .NET base class library. Until .NET 4 there even wasn't a File.EnumerateLines. And I would venture to say that such a functionality is more important than reverse iteration for most people.

It might be the case that you are working in a business domain where reverse iteration is common. My experience is the opposite. As a framework designer you can only guess who will use your framework and what features these people will demand. It is hard to draw the line.

平安喜乐 2025-01-13 18:15:00

它不可用,因为 IEnumerator 是仅向前迭代器。它只有一个 MoveNext() 方法。这使得该接口非常通用,并且是 Linq 的核心。有很多现实世界的集合无法向后迭代,因为这需要存储。例如,大多数流都是这样的。

Linq 提供了带有 Reverse() 扩展方法的解决方案。它的工作原理是首先存储元素,然后向后迭代它们。然而,这可能非常浪费,它需要 O(n) 存储。它缺少对已经可索引的集合的可能优化。您可以修复:

static class Extensions {
    public static IEnumerable<T> ReverseEx<T>(this IEnumerable<T> coll) {
        var quick = coll as IList<T>;
        if (quick == null) {
            foreach (T item in coll.Reverse()) yield return item;
        }
        else {
            for (int ix = quick.Count - 1; ix >= 0; --ix) {
                yield return quick[ix];
            }
        }
    }
}

示例用法:

        var list = new List<int> { 0, 1, 2, 3 };
        foreach (var item in list.ReverseEx()) {
            Console.WriteLine(item);
        }

您需要对 LinkedList 进行专门化,因为它没有实现 IList,但仍然允许通过 LastLinkedListNode.Previous 属性。尽管不使用该类要好得多,但它的 CPU 缓存局部性很差。当您不需要便宜的插入时,始终青睐 List。它可能看起来像这样:

    public static IEnumerable<T> ReverseEx<T>(this LinkedList<T> list) {
        var node = list.Last;
        while (node != null) {
            yield return node.Value;
            node = node.Previous;
        }
    }

It isn't available because IEnumerator is a forward only iterator. It only has a MoveNext() method. That makes the interface very universal and the core of Linq. There are lots of real world collections that cannot be iterated backwards because that requires storage. Most streams are like that for example.

Linq provides a solution with the Reverse() extension method. It works by storing the elements first, then iterating them backwards. That however can be very wasteful, it requires O(n) storage. It is missing a possible optimization for collections that are already indexable. Which you can fix:

static class Extensions {
    public static IEnumerable<T> ReverseEx<T>(this IEnumerable<T> coll) {
        var quick = coll as IList<T>;
        if (quick == null) {
            foreach (T item in coll.Reverse()) yield return item;
        }
        else {
            for (int ix = quick.Count - 1; ix >= 0; --ix) {
                yield return quick[ix];
            }
        }
    }
}

Sample usage:

        var list = new List<int> { 0, 1, 2, 3 };
        foreach (var item in list.ReverseEx()) {
            Console.WriteLine(item);
        }

You'll want to make a specialization for LinkedList since it doesn't implement IList<T> but still allows quick backwards iteration through the Last and LinkedListNode.Previous properties. Although it is much better to not use that class, it has lousy CPU cache locality. Always favor List<T> when you don't need cheap inserts. It could look like this:

    public static IEnumerable<T> ReverseEx<T>(this LinkedList<T> list) {
        var node = list.Last;
        while (node != null) {
            yield return node.Value;
            node = node.Previous;
        }
    }
圈圈圆圆圈圈 2025-01-13 18:15:00

线索就在OP的最后一行:在列表和链接列表上使用它。

因此,对于 List 来说,这个可以很好地工作:

    public static IEnumerable<T> AsReverseEnumerator<T>(this IReadOnlyList<T> list)
    {
        for (int i = list.Count; --i >= 0;) yield return list[i];
    }

使用 IReadOnlyList 在其工作方面提供了很大的灵活性。

对于 LinkedLists 来说,类似的事情也是可能的。

The clue is in the OP's final line: using this on Lists and LinkedLists.

So, for a List, this one would work nicely:

    public static IEnumerable<T> AsReverseEnumerator<T>(this IReadOnlyList<T> list)
    {
        for (int i = list.Count; --i >= 0;) yield return list[i];
    }

Using IReadOnlyList give a lot of flexibility in terms of what it will work on.

Something similar would be possible for LinkedLists.

烟花易冷人易散 2025-01-13 18:15:00

这个问题涉及一个枚举器,而不是一个枚举。
如果必须返回 IEnumerator(例如,当绑定到 wpf / uwp / winui 中的自定义数据源对象时),您可以这样做:

var reverseList = myList.AsEnumerable().Reverse().ToList();

return reverseList.GetEnumerator()

丑陋、复杂且有效,即完全遵守框架指南。

The question concerns an enumerator, not an enumeration.
If you must return an IEnumerator (e.g. when binding to a custom datasource object in wpf / uwp / winui), you can do it like this:

var reverseList = myList.AsEnumerable().Reverse().ToList();

return reverseList.GetEnumerator()

Ugly, convoluted and working, i.e. fully adhering to Framework Guidelines.

野却迷人 2025-01-13 18:15:00

是的,你可以轻松做到。

只需使用 Stack

就像

Stack<int> stack = new Stack<int>(collection);
IEnumerator<int> enumerator = stack.GetEnumerator();
while (enumerator.MoveNext())
{
    //Do stuff
}

Yes, you can do it easily.

Just use Stack<T>

Like

Stack<int> stack = new Stack<int>(collection);
IEnumerator<int> enumerator = stack.GetEnumerator();
while (enumerator.MoveNext())
{
    //Do stuff
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文