解离或重做的Python等价物?
我正在学习Python,我有一种情况,我想使用迭代器中的项。棘手的部分是,在某些条件下,我想“取消迭代”。也就是说,在循环之前将一个项放回迭代器的前面 例如,假设我正在从树上摘苹果。我的果篮只能装10公斤,还需要倒空。但我必须先摘下每一个苹果,然后才能称重,并确定这个苹果是否会超过篮子的容量 在Perl之类的语言中,我可以解离或重做的Python等价物?,python,redo,Python,Redo,我正在学习Python,我有一种情况,我想使用迭代器中的项。棘手的部分是,在某些条件下,我想“取消迭代”。也就是说,在循环之前将一个项放回迭代器的前面 例如,假设我正在从树上摘苹果。我的果篮只能装10公斤,还需要倒空。但我必须先摘下每一个苹果,然后才能称重,并确定这个苹果是否会超过篮子的容量 在Perl之类的语言中,我可以unshift()将苹果放回树上,然后让循环表达式重新拾取苹果: while ($apple = shift(@tree)) { $wt = weight($apple);
unshift()
将苹果放回树上,然后让循环表达式重新拾取苹果:
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
unshift(@tree, $apple);
} else {
push(@basket, $element);
}
}
或者我也可以使用redo
,它在块的顶部恢复处理,而不计算循环表达式。因此,同样的苹果可以在篮子清空后重新加工
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
redo;
} else {
push(@basket, $apple);
}
}
对于这类问题,什么样的解决方案才是最有说服力的?为什么要在else子句总是出现的时候取消移位呢
for apple in tree:
if (apple.weight + basket.weight) > 10:
send(basket)
basket.clear()
basket.add(apple)
无论如何,我相当肯定Python没有您想要的那种行为。在Python中,没有通用的方法将值推入迭代器。堆栈或链表更适合这种情况 如果您正在迭代列表或其他内容,当然可以手动将该项添加回列表。但是你也可以迭代那些不能以这种方式操作的对象 如果您想使用python实现该算法,那么必须选择一个允许您想要使用的操作的数据结构。我建议使用
.push()
和.pop()
方法将列表视为堆栈
我正在学习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)
当我写这篇文章时,@Patrick已经提出了同样的建议。但是,既然我已经写了它,我将以任何方式粘贴代码,并在Patrick的代码标记方法中添加注释
import random
apples=[random.randint(1,3) for j in range(10)]
print 'apples',apples
basket=[]
y=6
baskets=[]
for i in range(len(apples)):
if sum(basket+[apples[i]])>y:
#basket is full
baskets.append(basket)#basket.send()
basket=[]#basket.empty()
basket.append(apples[i])#add apple to basket
print 'baskets',baskets
虽然这不会弹出()原始迭代器中的苹果。如果这也是你想要的行为,请注意
输出
apples [1, 1, 3, 3, 1, 1, 3, 3, 2, 3]
baskets [[1, 1, 3], [3, 1, 1], [3, 3]]
您正在寻找一个生成器,一个迭代器,可以通过send()方法接收对其内部状态的修改 我会这么说。不要试图将迭代器包装在生成器表达式中,使您可以“回溯”或类似的复杂操作,而是使用while循环,就像在Perl中一样,随便你 实现的简单转换(忽略的优化): 或者,您可以使用带有有序序列索引的类
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))
如果您不喜欢“simple”参数,请查看上面(链接)线程中提到的
collections.deque
迭代器。如果您不想遵循其他人的建议,只删除else子句,您可以编写自己的unshift
函数,该函数将以类似于perl的方式使用任何iterable:
class UnshiftableIterable(object):
def __init__(self, iterable):
self._iter = iter(iterable)
self._unshifted = [] # empty list of unshifted stuff
def __iter__(self):
while True:
if self._unshifted:
yield self._unshifted.pop()
else:
yield self._iter.next()
def unshift(self, item):
self._unshifted.append(item)
然后在代码中:
it = UnshiftableIterable(tree)
for apple in tree:
if weigth(basket) + weight(apple) > MAX_WEIGHT:
send(basket)
basket = []
it.unshift(apple)
else:
basket.append(apple)
对不可移动的的一些测试:
it = UnshiftableIterable(xrange(5))
for i in it:
print '*',
if i == 2:
it.unshift(10)
else:
print i,
# output: * 0 * 1 * * 10 * 3 * 4
顺便说一句,您真正想要的是列表。插入(0,您的对象)回到关于弹劾unshift的原始问题,operator.delitem可用于实现一个简单的非OO函数:
from operator import delitem
def unshift(l,idx):
retval = l[0]
delitem(l,0)
return retval
x = [2,4,6,8]
firstval = unshift(x,0)
print firstval,x
2[4,6,8]只是澄清一下:Python的内置迭代器没有他想要的那种行为。这似乎是最简单的解决方案。谢谢您的UnshiftableIterator
不是迭代器(它没有next()
方法)。它是可测试的(它有\uu iter\uu()
方法)。@J.F.Sebastian:True。更改名称以反映这一点。树中的苹果:
->树中的苹果:
。否则,将永远不会使用未移位的值。感谢您提供的示例。很高兴看到如何创建一个iterable类,即使我没有在这个特殊情况下使用这个解决方案。如果$wt>10,那么就有一个无限循环(第一个示例会消耗所有内存,第二个示例永远不会停止)。@J.F:你说得对,但是在这种情况下,可以安全地假设没有一个苹果会超过10kg。谢谢,这回答了我最初提出的关于如何实现类取消移位操作的问题。感谢您提供有关send()的提示!我不确定我会在这种情况下使用它,但知道未来会很好。谢谢,记住从这个问题上退一步是很好的。与其把重点放在反移位这样的机制上,不如用一种更简单的方法来解决真正的问题。这不是反移位,而是移位。
it = UnshiftableIterable(tree)
for apple in tree:
if weigth(basket) + weight(apple) > MAX_WEIGHT:
send(basket)
basket = []
it.unshift(apple)
else:
basket.append(apple)
it = UnshiftableIterable(xrange(5))
for i in it:
print '*',
if i == 2:
it.unshift(10)
else:
print i,
# output: * 0 * 1 * * 10 * 3 * 4
from operator import delitem
def unshift(l,idx):
retval = l[0]
delitem(l,0)
return retval
x = [2,4,6,8]
firstval = unshift(x,0)
print firstval,x