我有一个迭代器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))
有人知道是否有更好的解决方案吗?
我知道我的解决方案有效但似乎很奇怪(至少对我而言)我自己编写一个模块来完成这样一个简单的任务。我正在寻找一个简单的单线或内置解决方案(如果存在)
答案 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