我正在学习Python,我有一种情况,我想从迭代器中使用项目.棘手的部分是在某些条件下,我想"不迭代".也就是说,在循环之前将项放回到迭代器的前面.
例如,假设我从树上摘苹果.我的水果篮在需要清空之前只能容纳10公斤.但是我必须在我称之前挑选每个苹果,并确定这个苹果是否会超过篮子的容量.
在像Perl这样的语言中,我可以unshift()将苹果重新放回树上,然后让循环表达式重新选择苹果:
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
unshift(@tree, $apple);
} else {
push(@basket, $element);
}
}
Run Code Online (Sandbox Code Playgroud)
或者我也可以使用redo,它在块的顶部恢复处理,而不评估循环表达式.因此,在篮子被清空后,同样的苹果可以被重新加工.
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
redo;
} else {
push(@basket, $apple);
}
}
Run Code Online (Sandbox Code Playgroud)
对于这类问题,什么是最pythonic的解决方案?
Fed*_*oni 16
我正在学习Python,我有一种情况,我想从迭代器中使用项目.棘手的部分是在某些条件下,我想"不迭代".也就是说,在循环之前将项放回到迭代器的前面.
这是一个简单的解决方案:
class MyIterator(object): # undo-able iterator wrapper
def __init__(self, iterable):
super(MyIterator, self).__init__()
self.iterator = iter(iterable)
self.stack = []
def __iter__(self):
return self
def next(self):
if self.stack:
return self.stack.pop()
return self.iterator.next() # Raises StopIteration eventually
def undo(self, item):
self.stack.append(item)
Run Code Online (Sandbox Code Playgroud)
for i in MyIterator(xrange(5)): print i
0
1
2
3
4
Run Code Online (Sandbox Code Playgroud)
rng = MyIterator(xrange(5))
rng.next()
0
rng.next()
1
rng.undo(1)
rng.next()
1
Run Code Online (Sandbox Code Playgroud)
Pat*_*ick 13
当else子句总是应该出现时,为什么要烦恼呢?
for apple in tree:
if (apple.weight + basket.weight) > 10:
send(basket)
basket.clear()
basket.add(apple)
Run Code Online (Sandbox Code Playgroud)
无论如何,我很确定Python没有你想要的那种行为.
我会说最Pythonic解决方案是最简单的解决方案.而不是试图将迭代器包装在允许你"回溯"或类似复杂的东西的生成器表达式中,使用while循环,就像在Perl中一样!迭代器不会与变异混合得非常好.
简单翻译您的实现(忽略@Patrick的优化):
while tree:
apple = tree.pop(0)
if apple.weight + basket.weight > 10:
basket.send()
basket.clear()
tree.insert(0, apple) # Put it back.
else:
basket.append(apple)
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用peek具有有序序列索引的类似功能:
while tree:
apple = tree[0] # Take a peek at it.
if apple.weight + basket.weight > 10:
basket.send()
basket.clear()
else:
basket.append(tree.pop(0))
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢"简单"参数,请查看collections.deque上面(链接)线程中提到的迭代器.