首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何制作更具表现力的python迭代器?就像c++迭代器一样

如何制作更具表现力的python迭代器?就像c++迭代器一样
EN

Stack Overflow用户
提问于 2012-04-05 20:34:23
回答 5查看 2.1K关注 0票数 5

首先,我回顾了quickly.for示例的c++风格迭代器:

代码语言:javascript
运行
复制
//--- Iterating over vector with iterator.
vector<int> v;
. . .
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
    cout << *it << endl;
}

它是灵活的。很容易改变底层的容器类型。例如,您可能会在以后决定插入和删除的数量非常多,以至于列表比向量更有效。它还有许多有用的成员函数。向量的许多成员函数使用迭代器,例如,assign、insert或erase。此外,我们可以双向使用迭代器(如果支持),例如++,--。这对于解析像对象这样的流很有用。

python的问题是:1:目前python for循环语法不如c++ for灵活。2:当iter.end()没有更多的时候,python会抛出异常,而不是"it != next()“风格。这是不灵活的。

问题1:我上面的想法正确吗?

好的。我的问题来了,如何实现一个像c++迭代器一样强大的python迭代器?目前,python for循环语法不如c++ for灵活。我还找到了一些可能的解决方案,比如http://www.velocityreviews.com/forums/t684406-pushback-iterator.html。但它要求用户push_back一个东西,而不是询问迭代器--。

问题2:在python中实现双向迭代器最好的是什么?就像http://www.cplusplus.com/reference/std/iterator/BidirectionalIterator/一样。伪代码如下:

代码语言:javascript
运行
复制
it = v.begin();
while( it!=v.end()) {
    //do sth here

    if (condition1)
        ++it;//suppose this iterator supports ++
    if(condition2)
      --it;//suppose this iterator supports --
}

其主要特点是: 1)双向,2)更简单的“结束”检查。"++“或"--”运算符或公共函数都无关紧要(它们在语义上没有区别)。

谢谢,

更新:我从答案中得到了一些可能的解决方案:

代码语言:javascript
运行
复制
i = 0
while i < len(sequence): # or i < len and some_other_condition
    star_it = sequence[i]
    if condition_one(star_it):
        i += 1
    if condition_two(star_it):
        i = max(i - 1, 0)

然而,与数组不同,列表的随机访问应该是O(n)。我认为python内部的"list“对象是使用类似链表的东西实现的。因此,这种while循环解决方案效率不高。然而,在c++中,我们有“随机迭代器”,“双向迭代器”。我应该如何获得更好的解决方案?谢谢。

EN

回答 5

Stack Overflow用户

发布于 2012-04-05 21:35:40

对于大多数情况,Python的for和迭代器是最简单的。这是他们的目标,他们不应该为了灵活性而妥协--他们缺乏灵活性不是问题。

对于不能使用for循环的少数情况,C++迭代器可能更简单。但是在Python语言中总有一种方法可以做到这一点,这种方法并不比使用C++迭代器复杂。

如果您需要将推进迭代器与循环分开,只需使用while循环:

代码语言:javascript
运行
复制
it = iter(obj)

try:
    while True: # or some secondary break condition other than StopIteration
        star_it = next(it)
        if condition_one(star_it):
            star_it = next(it)
except StopIteration:
    pass # exhausted the iterator

我只能想到两种情况,在Python中--it是有意义的。

第一个是你正在迭代一个序列。在这种情况下,如果需要向后返回,则根本不要使用迭代器--只需使用带有while循环的计数器:

代码语言:javascript
运行
复制
i = 0
while i < len(sequence): # or i < len and some_other_condition
    star_it = sequence[i]
    if condition_one(star_it):
        i += 1
    if condition_two(star_it):
        i = max(i - 1, 0)

第二个是如果你在一个双向链表上迭代。在这种情况下,同样,不要使用迭代器--只需正常地遍历节点:

代码语言:javascript
运行
复制
current = node
while current: # or any break condition
    if condition_one(current):
        current = current.next
    if condition_two(star_it):
        current = current.prev

在无序集合中,比如setdict,你可以使用它,但是你不能使用上面提到的任何一种方法。然而,在这种情况下,--it就没有意义了。由于集合在语义上是无序的,因此以前到达的任何项都是合适的--而不仅仅是实际的前一项。

因此,为了知道要返回的正确对象,您需要内存,或者通过迭代mydict.values()tuple(myset)之类的序列并使用计数器,或者通过在执行过程中组装以前的值序列并使用上面的while循环和next而不是for循环。

票数 5
EN

Stack Overflow用户

发布于 2012-04-05 22:09:18

您提到的几种情况的解决方案:

  1. 您要替换基础容器中的对象。对于字典,遍历键或项,而不仅仅是值:

对于键,my_dict.iteritems()中的值: if conditiion( value ):my_dictkey = new_value

对于列表,请使用enumerate()

对于索引,item in enumerate(my_list):if condition(item):my_listindex =new_item

  • 您需要一个具有一个"look-ahead“值的迭代器。你可能会使用针对特定情况量身定做的东西,但这里有一个针对一般情况的秘诀:

def iter_with look_ahead(iterable,sentinel=None):iterable,it_ahead = itertools.tee(iterable) next(it_ahead,None)返回当前的izip_longest(iterable,it_ahead,fillvalue=sentinel),look_ahead in iter_with look_ahead(tokens):#要反向迭代的任何

  • 。对支持它的容器使用reversed()

  • 你想要随机访问。只需将您的迭代器转换为列表并使用索引即可:

my_list = list(my_iterable)

票数 1
EN

Stack Overflow用户

发布于 2012-04-05 21:33:59

实际上,C++迭代器系统并不是很好。迭代器类似于指针,它们有自己的问题:

safely

  • inversion issues:std::for_each(end, begin, func);

  • mismatch issues:std::for_each(v0.begin(), v2.end(), func);

  • singular values:v.end() cannot be dereferenced safely
  • inversion issues:std::for_each(end, begin, func);
  • mismatch issues:v.end()#en2#dereferenced safely
  • inversion issues:std::for_each(end, begin, func);
  • mismatch issues:issues

Python方法在这方面要好得多(虽然exception的使用一开始可能会让人非常惊讶,但它确实有助于定义嵌套迭代器),因为与其名称相反,Python迭代器更类似于Range

Range的概念比C++11引入的range-for循环结构要好得多:

代码语言:javascript
运行
复制
for (Object& o: range) {
}

使用迭代器可以实现的任何事情都可以通过范围来实现,尽管可能需要一些时间才能意识到这一点,对于我们这些接受过C++类指针迭代器教育的人来说,一些翻译一开始似乎是超现实主义的。例如,子范围可以完美地表示为:

代码语言:javascript
运行
复制
for (Object& o: slice(range, 2, 9)) {
}

其中slice将接受range中位置为[2, 9)的所有元素。

因此,与其与您的语言(Python)作斗争,不如深入研究它并拥抱它的风格。与一种语言作战通常是一场失败的战斗,学习它的习惯用法,变得高效。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10028693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档