C# 指针、迭代器和泛型

发布于 2025-01-02 20:50:34 字数 1083 浏览 2 评论 0原文

我很困惑

如何在 C# 中像 C++ 迭代器一样使用迭代器?我找不到 Begin() 或 End() 访问器,我什至不知道如何声明迭代器。我读过有关 Ienumerator 的内容。我的目标是实现合并功能。这是我用 C++ 编写的合并函数的一部分。大多数情况下,我正在寻找与所示内容等效的 C#,但我将使用引用类型而不是整数。

void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator      leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full)
{

    while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached
    {
        if(*right < *left)      //right < left so insert right to the output vector and advance the iterators
        {
            *full++ = *right++;
        }
        else                   //left < right so insert left to the output vector and advance the iterators
        {
            *full++ = *left++;
        }
    }

    while(left != leftEnd)    //copy any remaining elements into the output from left 
    {
        *full++ = *left++;
    }
}

另外,我应该使用什么集合? (目前我一直在尝试 ListLinkedList)。

I am greatly stumped

How can I use an iterator in C# like a C++ iterator? I cannot find a Begin() or End() accessor, I cannot even find out how to declare an iterator. I have read about the Ienumerator. My goal is to implement the Merge Function. Here is part of my Merge function written in C++. Mostly, I am looking for the C# equivalent of what is shown, except I will be using a Reference type rather than integers.

void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator      leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full)
{

    while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached
    {
        if(*right < *left)      //right < left so insert right to the output vector and advance the iterators
        {
            *full++ = *right++;
        }
        else                   //left < right so insert left to the output vector and advance the iterators
        {
            *full++ = *left++;
        }
    }

    while(left != leftEnd)    //copy any remaining elements into the output from left 
    {
        *full++ = *left++;
    }
}

Also, what collection(s) should I use? (currently I have been trying List<T> and LinkedList<T>).

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

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

发布评论

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

评论(4

舟遥客 2025-01-09 20:50:34

听起来您想要类似的东西:

bool leftValid = left.MoveNext();
bool rightValid = right.MoveNext();

while (leftValid && rightValid)
{
    if (right.Current < left.Current)
    {
        full.Add(right.Current);
        rightValid = right.MoveNext();
    }
    else
    {
        full.Add(left.Current);
        leftValid = left.MoveNext();
    }
}

while (leftValid)
{
    full.Add(left.Current);
    leftValid = left.MoveNext();    
}

while (rightValid)
{
    full.Add(right.Current);
    rightValid = right.MoveNext();    
}

Here full would need to be some sort of IList - .NET 迭代器不允许您对底层集合进行更改。

不应该尝试编写“桥接”代码来让您使用像C++迭代器一样的.NET迭代器;当您使用 .NET 时,最好尝试开始考虑 .NET 迭代器。

请注意,在 .NET 中传递迭代器的情况很少见。将您的方法设置为 IEnumerable 参数会更自然,并执行以下操作:

using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator())
{
    using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator())
    {
        // Code as above, just using leftIterator and rightIterator
        // instead of left and right
    }
}

It sounds like you want something like:

bool leftValid = left.MoveNext();
bool rightValid = right.MoveNext();

while (leftValid && rightValid)
{
    if (right.Current < left.Current)
    {
        full.Add(right.Current);
        rightValid = right.MoveNext();
    }
    else
    {
        full.Add(left.Current);
        leftValid = left.MoveNext();
    }
}

while (leftValid)
{
    full.Add(left.Current);
    leftValid = left.MoveNext();    
}

while (rightValid)
{
    full.Add(right.Current);
    rightValid = right.MoveNext();    
}

Here full would need to be some sort of IList<T> - .NET iterators don't let you make changes to the underlying collection.

You shouldn't try to write "bridging" code to let you use .NET iterators like C++ ones; it's much better to try to start thinking in terms of the .NET iterators when you're using .NET.

Note that it's quite rare to pass iterators around in .NET. It would be more natural to make your method to IEnumerable<T> parameters, and do something like:

using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator())
{
    using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator())
    {
        // Code as above, just using leftIterator and rightIterator
        // instead of left and right
    }
}
雪化雨蝶 2025-01-09 20:50:34

.net 容器不支持 C++ 风格的迭代器。他们唯一拥有的是一个

  • 名为 IEnumerator的简单前向迭代器,
  • 它无法修改集合
  • ,也不是随机访问
  • ,无法复制(某些集合具有可以复制的值类型迭代器) ,但这是一项棘手的业务并且很少使用)
  • ,并且在大多数集合上,每当您修改集合时,它们也会变得无效。

几乎它们唯一能做的就是在 foreach 语句中进行迭代。


您可能需要查看允许随机访问的 IList 接口,但仅在支持快速索引的集合上受支持。在这样的集合上,您可以使用索引实现就地合并排序。

void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full)

然后使用 container[left] 而不是 *left


这样做的不幸后果是,您无法像 C++ 那样实现高效的就地容器无关排序函数。

.net containers don't support C++ style iterators. The only thing they have is a

  • simple forward iterator called IEnumerator<T>
  • which can't modify the collection
  • isn't random access
  • can't be copied (some collections have value type iterators which can be copied, but that's tricky business and rarely used)
  • and on most collections also gets invalidated whenever you modify the collection

Pretty much the only thing they can do is being iterated over in a foreach statement.


You might want to look into the IList<T> interface which allows random access, but is only supported on collections which support fast indexing. On such a collection you could implement in-place merge sort by using indices.

void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full)

and then use container[left] instead of *left.


Unfortunate consequence of this is, that you can't implement an efficient in-place container agnostic sorting function like C++ has.

靖瑶 2025-01-09 20:50:34

我认为您需要 GetEnumerator()、MoveNext() 和 Current。

通常,您可以只使用 foreach 进行迭代,但您的情况很特殊。

事实上,不要使用“full”,而是将其组织为迭代器块并延迟合并两个可枚举值。

IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right)
{
    ... yield return Min<T>(left.Current, right.Current); ..,
}

I think you want GetEnumerator(), MoveNext(), and Current.

Normally, you can just use foreach to iterate, but your case is special.

If fact, rather than using "full", organize this as an iterator block and merge two enumerables lazily.

IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right)
{
    ... yield return Min<T>(left.Current, right.Current); ..,
}
最后的乘客 2025-01-09 20:50:34

您可以使用具有固定大小的数组,或 List,在其他语言中也称为 ArrayList。可以通过索引器 (list[i]) 访问它们的项目,并且可以使用 list.Add(item); 附加项目。它们会自动生长。 LinkedLists 无法通过索引器访问,必须进行遍历。

您可以声明这样的方法

void merge(IEnumerator<int> left, IEnumerator<int> right, 
           List<int> full)
{
    // Jon Skeet's code goes here
}

您可以获得像这样的枚举器

IEnumerable<int> intEnumerable = ...;
IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator();

IEnumerable 由大多数通用集合类型实现。非泛型集合通常实现 IEnumerable

(针对@CodeInChaos 的评论进行编辑)。

You can use arrays, which have a fixed size, or List<T>, which are also called ArrayLists in other languages. Their items can be accessed through an indexer (list[i]) and items can be appended with list.Add(item);. They grow automatically. LinkedLists cannot be accessed via an indexer and must be traversed.

You would declare the method like this

void merge(IEnumerator<int> left, IEnumerator<int> right, 
           List<int> full)
{
    // Jon Skeet's code goes here
}

You can get an enumerator like this

IEnumerable<int> intEnumerable = ...;
IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator();

IEnumerable<T> is implemented by most generic collection types. Non generic collections usually implement IEnumerable.

(Edited in response to @CodeInChaos's comment).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文