C#指针,迭代器和泛型

时间:2012-02-05 17:59:05

标签: c# c++ generics collections iterator

我非常难过

如何在C#中使用迭代器,就像C ++迭代器一样?我找不到Begin()或End()访问器,我甚至无法找到如何声明迭代器。我读过关于Ienumerator的文章。我的目标是实现合并功能。这是我用C ++编写的Merge函数的一部分。大多数情况下,我正在寻找所显示内容的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++;
    }
}

另外,我应该使用哪些系列? (目前我一直在尝试List<T>LinkedList<T>)。

4 个答案:

答案 0 :(得分:7)

听起来你想要这样的东西:

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();    
}

这里full需要某种IList<T> - .NET迭代器不允许你对底层集合进行更改。

不应该尝试编写“桥接”代码,以便让你使用像C ++那样的.NET迭代器;当你使用.NET时,尝试用.NET迭代器开始思考会好得多。

请注意,在.NET中传递迭代器是非常罕见的。将方法设置为IEnumerable<T>参数更自然,并执行以下操作:

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
    }
}

答案 1 :(得分:3)

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

  • 简单的前向迭代器IEnumerator<T>
  • 无法修改集合
  • 不是随机访问
  • 无法复制(某些集合具有可以复制的值类型迭代器,但这很棘手,很少使用)
  • 并且在修改集合时,大多数集合也会失效

他们唯一可以做的就是在foreach语句中进行迭代。


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

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

然后使用container[left]代替*left


这样做的不幸后果是,您无法像C ++那样实现有效的就地容器不可知排序功能。

答案 2 :(得分:2)

我想你想要GetEnumerator(),MoveNext()和Current。

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

如果事实,而不是使用“完整”,将其组织为迭代器块并懒惰地合并两个枚举。

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

答案 3 :(得分:0)

您可以使用具有固定大小或List<T>的数组,这些数组在其他语言中也称为ArrayLists。他们的项目可以通过索引器(list[i])访问,项目可以附加list.Add(item);。它们会自动增长。 <{1}}无法通过索引器访问,必须遍历。

你会声明像这样的方法

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<T>

(编辑回应@ CodeInChaos的评论)。