Python迭代器中的hasNext?

时间:2009-12-27 18:04:51

标签: python iterator

Python迭代器没有得到hasNext方法吗?

15 个答案:

答案 0 :(得分:178)

使用StopIteration替代next(iterator, default_value)

exapmle:

>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None

因此,如果您不想要异常方式,则可以检测迭代器结尾的None或其他预先指定的值。

答案 1 :(得分:84)

不,没有这样的方法。迭代的结束由异常指示。请参阅documentation

答案 2 :(得分:33)

如果你真的需要一个has-next功能(因为你只是忠实地用Java中的参考实现转录算法,比如说,或者因为你正在写一个原型< em>将需要在完成时轻松转录为Java),通过一个小的包装类很容易获得它。例如:

class hn_wrapper(object):
  def __init__(self, it):
    self.it = iter(it)
    self._hasnext = None
  def __iter__(self): return self
  def next(self):
    if self._hasnext:
      result = self._thenext
    else:
      result = next(self.it)
    self._hasnext = None
    return result
  def hasnext(self):
    if self._hasnext is None:
      try: self._thenext = next(self.it)
      except StopIteration: self._hasnext = False
      else: self._hasnext = True
    return self._hasnext

现在像

x = hn_wrapper('ciao')
while x.hasnext(): print next(x)

发射

c
i
a
o

根据需要。

请注意,使用next(sel.it)作为内置函数需要Python 2.6或更高版本;如果您使用的是旧版本的Python,请使用self.it.next()代替(在示例用法中类似于next(x))。 [[你可能会合理地认为这个说明是多余的,因为Python 2.6已经存在了一年多了 - 但是当我在回复中使用Python 2.6功能时,一些评论者或其他人认为有义务指出他们 2.6的功能,因此我试图阻止这样的评论一次; - )]]

答案 3 :(得分:11)

除了所有提到的StopIteration之外,Python“for”循环只是做你想要的:

>>> it = iter("hello")
>>> for i in it:
...     print i
...
h
e
l
l
o

答案 4 :(得分:7)

从任何迭代器对象中尝试__length_hint __()方法:

iter(...).__length_hint__() > 0

答案 5 :(得分:5)

hasNext稍微转换为StopIteration例外,例如:

>>> it = iter("hello")
>>> it.next()
'h'
>>> it.next()
'e'
>>> it.next()
'l'
>>> it.next()
'l'
>>> it.next()
'o'
>>> it.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

答案 6 :(得分:4)

你可以使用tee itertools.tee迭代器,并在teed迭代器上检查StopIteration

答案 7 :(得分:3)

没有。最相似的概念很可能是StopIteration exception.

答案 8 :(得分:2)

我相信python只有next(),并且根据文档,它会抛出异常,因为没有更多的元素。

http://docs.python.org/library/stdtypes.html#iterator-types

答案 9 :(得分:1)

引导我搜索此内容的用例如下

def setfrom(self,f):
    """Set from iterable f"""
    fi = iter(f)
    for i in range(self.n):
        try:
            x = next(fi)
        except StopIteration:
            fi = iter(f)
            x = next(fi)
        self.a[i] = x 

其中hasnext()可用,可以做

def setfrom(self,f):
    """Set from iterable f"""
    fi = iter(f)
    for i in range(self.n):
        if not hasnext(fi):
            fi = iter(f) # restart
        self.a[i] = next(fi)
对我来说更清洁。显然,你可以通过定义实用程序类来解决问题,但是接下来发生的事情就是你有大量二十多种不同的几乎相同的变通方法,每种方法都有它们的怪癖,如果你想重用使用不同变通方法的代码,你必须要么在您的单个应用程序中具有多个近似等效,或者选择并重写代码以使用相同的方法。 “做一次,做得好”的格言失败了。

此外,迭代器本身需要运行内部“hasnext”检查以查看是否需要引发异常。然后隐藏此内部检查,以便需要通过尝试获取项目,捕获异常并在抛出时运行处理程序来进行测试。这是不必要的隐藏IMO。

答案 10 :(得分:0)

建议的方式是 StopIteration 。 请参阅tutorialspoint

中的斐波那契示例
#!usr/bin/python3

import sys
def fibonacci(n): #generator function
   a, b, counter = 0, 1, 0
   while True:
      if (counter > n): 
         return
      yield a
      a, b = b, a + b
      counter += 1
f = fibonacci(5) #f is iterator object

while True:
   try:
      print (next(f), end=" ")
   except StopIteration:
      sys.exit()

答案 11 :(得分:0)

一个非常有趣的问题,但是这个“ hasnext”设计已经被放入leetcode中: https://leetcode.com/problems/iterator-for-combination/

这是我的实现方式

class CombinationIterator:

def __init__(self, characters: str, combinationLength: int):
    from itertools import combinations
    from collections import deque
    self.iter = combinations(characters, combinationLength)
    self.res = deque()


def next(self) -> str:
    if len(self.res) == 0:
        return ''.join(next(self.iter))
    else:
        return ''.join(self.res.pop())


def hasNext(self) -> bool:
    try:
        self.res.insert(0, next(self.iter))
        return True
    except:
        return len(self.res) > 0

答案 12 :(得分:0)

也可以实现一个辅助生成器来包装任何迭代器并回答问题是否有下一个值:

Try it online!

def has_next(it):
    first = True
    for e in it:
        if not first:
            yield True, prev
        else:
            first = False
        prev = e
    if not first:
        yield False, prev

for has_next_, e in has_next(range(4)):
    print(has_next_, e)

输出:

True 0
True 1
True 2
False 3

此方法的主要且可能唯一的缺点是它会多读一个元素,对于大多数任务来说完全没问题,但对于某些任务可能是不允许的,特别是如果 has_next() 的用户不是意识到这种预读逻辑,可能会误用它。

上面的代码也适用于无限迭代器。

实际上,对于我曾经编写过这种 has_next() 的所有情况,已经完全足够了,并且没有引起任何问题,而且实际上非常有帮助。您只需要了解它的预读逻辑。

答案 13 :(得分:-1)

这样的问题/问题的好方法是检查我们在dir中的内容(object / method / iterator / type / class / ...)

您会看到dir(iterator)返回__length_hint__

iterator.__length_hint__()为正,直到迭代结束。

就是这样。

答案 14 :(得分:-2)

我解决问题的方法是保持迭代的对象数量,到目前为止。我想使用对实例方法的调用来迭代一个集合。由于我知道集合的长度以及到目前为止计算的项目数量,因此我实际上使用了hasNext方法。

我的代码的简单版本:

class Iterator:
    # s is a string, say
    def __init__(self, s):
        self.s = set(list(s))
        self.done = False
        self.iter = iter(s)
        self.charCount = 0

    def next(self):
        if self.done:
            return None
        self.char = next(self.iter)
        self.charCount += 1
        self.done = (self.charCount < len(self.s))
        return self.char

    def hasMore(self):
        return not self.done

当然,这个例子是一个玩具,但你明白了。如果没有办法获得迭代的长度,就像生成器等那样,这不会起作用。