检查迭代器是否已排序

时间:2015-06-24 08:20:20

标签: python iterator

我有一个迭代器it,我假设它已经排序但是我想提出异常,如果不是。

来自迭代器的数据不在内存中,因此我不想使用内置sorted()因为AFAIK它将整个迭代器放在列表中。

我现在使用的解决方案是将迭代器包装在这样的生成器函数中:

def checkSorted(it):
  prev_v = it.next()
  yield prev_v
  for v in it:
    if v >= prev_v:
      yield v
      prev_v = v
    else:
      raise ValueError("Iterator is not sorted")

所以我可以像这样使用它:

myconsumer(checkSorted(it))

有人知道是否有更好的解决方案吗?

我知道我的解决方案有效但似乎很奇怪(至少对我而言)我自己编写一个模块来完成这样一个简单的任务。我正在寻找一个简单的单线或内置解决方案(如果存在)

2 个答案:

答案 0 :(得分:3)

基本上你的解决方案几乎和它一样优雅(当然你可以把它放在一个实用程序模块中,如果你发现它通常很有用)。如果你想要它使用无限对象来减少代码,你可以使用它,但是你必须包含一个类定义,这会再次增加代码(除非你内联类定义):

def checkSorted(it):
    prev = type("", (), {"__lt__": lambda a, b: False})()

    for x in it:
        if prev < x:
            raise ValueError("Not sorted")
        prev = x
        yield x

第一行是使用type首先创建一个类然后实例化它。此类的对象比任何东西(无限对象)都要少。

执行一行的问题是你必须处理三个结构:你必须更新状态(赋值),抛出异常并进行循环。你可以通过使用语句轻松地执行这些操作,但是将它们变成oneliner将意味着你必须尝试将语句放在同一行 - 这反过来会导致循环问题和if - 构造

如果你想将整个事物放入表达式中,你将不得不使用肮脏的技巧来完成这些操作,iterutils的赋值和循环可以提供,并且可以使用{{1}来完成抛出生成器中的方法(也可以在表达式中提供):

throw

最后一个imap( lambda i, j: (i >= j and j or (_ for _ in ()).throw(ValueError("Not sorted"))), *(lambda pre, it: (chain([type("", (), {"__ge__": lambda a, b: True})()], pre), it))(*tee(it))) 是要检查的迭代器,表达式求值为已检查的迭代器。我同意它并不好看而且不明显它的作用,但你要求它(我认为你不想要它)。

答案 1 :(得分:2)

作为替代方案,我建议使用itertools.izip_longest(和python 3中的zip_longest)来创建包含连续对的生成器:

您可以使用tee从第一个可迭代创建2个独立的迭代器。

from itertools import izip_longest,tee

def checkSorted(it):
  pre,it=tee(it)
  next(it)
  for i,j in izip_longest(pre,it):
    if j:
      if i >= j:         
        yield i
      else:
        raise ValueError("Iterator is not sorted")
    else :
        yield i

演示:

it=iter([5,4,3,2,1])
print list(checkSorted(it))

[5, 4, 3, 2, 1]

it=iter([5,4,3,2,3])
print list(checkSorted(it))

Traceback (most recent call last):
  File "/home/bluebird/Desktop/ex2.py", line 19, in <module>
    print list(checkSorted(it))
  File "/home/bluebird/Desktop/ex2.py", line 10, in checkSorted
    raise ValueError("Iterator is not sorted")
ValueError: Iterator is not sorted

注意:实际上我认为没有必要产生你已经拥有它们的迭代值。所以我建议在{{1}中使用生成器表达式。函数并返回一个bool值:

all