Pythonic 相当于 unshift 或 redo?
我正在学习 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);
}
}
或者我也可以使用 redo
>,它在块的顶部恢复处理,而不评估循环表达式。 因此,在篮子清空后,可以重新加工同一个苹果。
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
redo;
} else {
push(@basket, $apple);
}
}
对于此类问题,最Pythonic的解决方案是什么?
I'm learning Python, and I have a situation where I want to consume items from an iterator. The tricky part is that under certain conditions, I want to "un-iterate." That is, put an item back onto the front of the iterator before I loop.
For example, suppose I'm picking apples from a tree. My fruit basket can only hold 10kg before it needs to be emptied. But I have to pick each apple before I can weigh it and determine if this apple would exceed the capacity of the basket.
In a language like Perl, I could unshift()
the apple back onto the tree, and then let the loop expression re-pick the apple:
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
unshift(@tree, $apple);
} else {
push(@basket, $element);
}
}
Or else I can also use redo
, which resumes processing at the top of block, without evaluating the loop expression. So the same apple can be re-processed, after the basket has been emptied.
while ($apple = shift(@tree)) {
$wt = weight($apple);
if ($wt + weight(@basket) > 10) {
send(@basket);
@basket = ();
redo;
} else {
push(@basket, $apple);
}
}
What would be the most pythonic solution for this kind of problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这是一个简单的解决方案:
Here's a simple solution:
当 else 子句应该总是出现时,为什么还要费心保持不变呢?
不管怎样,我相当确定 Python 不具备您正在寻找的那种行为。
Why bother with unshifting when the else clause should always occur?
Anyway, I'm fairly certain that Python doesn't have the sort of behavior you're looking for.
我想说最Pythonic的解决方案是最简单的< /a>. 不要尝试将迭代器包装在允许您“回溯”或类似复杂的东西的生成器表达式中,而是使用 while 循环,就像在 Perl 中一样! 迭代器与突变不能很好地混合,任何人。
简单翻译您的实现(忽略 @Patrick 的优化):
或者,您可以使用带有有序序列索引的类似
peek
的功能:如果您不喜欢“简单”参数,请查看中提到的
collections.deque
迭代器上面(链接的)线程。I'd say that the most Pythonic solution is the simplest one. Instead of trying to wrap an iterator in a generator expression that allows you to "backtrack" or something similarly complex, use a while loop, as you have in Perl! Iterators don't mix very nicely with mutation, anywho.
Simple translation of your implementation (ignoring @Patrick's optimization):
Or, you could use a
peek
-like functionality with ordered sequence indices:If you don't like the "simple" argument, check out the
collections.deque
iterators mentioned in the above (linked) thread.如果您不想遵循其他人的建议,仅删除 else 子句,您可以编写自己的
unshift
函数,该函数的工作方式类似于 perl 的任何可迭代对象:然后在您的代码中:
UnshiftableIterable 的一些测试:
If you don't want to follow the other's suggestion of just removing the else clause, you can write your own
unshift
function that will work in a way similar to perl's with any iterable:Then in your code:
Some testing of the
UnshiftableIterable
:您正在寻找一个生成器,一个可以通过 send() 方法接收对其内部状态的修改的迭代器
https://docs.python.org/howto/function.html#passing-values-into-a-generator
You're looking for a generator, an iterator that can receive modifications to its internal state via the send() method
https://docs.python.org/howto/functional.html#passing-values-into-a-generator
顺便说一句,你真正想要的是 list.insert(0,yourObject)
By the way, what you really want is list.insert(0,yourObject)
当我写这篇文章时,@Patrick 已经提出了同样的建议。 但既然我已经写好了,我无论如何都会粘贴代码,并在代码标记方法中添加来自 Patrick 的注释。
尽管这不会 pop() 原始迭代器中的苹果。 请备注这是否也是所需的行为。
输出
While I was writing this @Patrick already suggested the same thing. But since I have written it I will paste the code anyways, with comments in code marking methods from Patrick.
though this does not pop() the apples from the original iterator. Please remark if that's a desired behavior too.
the output
目前我的升级版本 pythonizer 无法处理
redo
但如果我添加它,我可能会像这样实现它:(注意:我必须将
send
更改为sendit
因为send
是在 perl 中预定义的。)Currently my upgraded version of pythonizer doesn't handle
redo
but if I added it, I would probably implement it like this:(Note: I had to change
send
tosendit
becausesend
is predefined in perl.)回到最初关于实现unshift的问题,operator.delitem可以用来实现一个简单的非OO函数:
2 [4, 6, 8]
Back to the original question about impementing unshift, operator.delitem can be used to implement a simple non-OO function:
2 [4, 6, 8]
在 python 中,没有通用的方法可以将值推入迭代器。 堆栈或链表更适合于此。
如果您要迭代列表或其他内容,当然您可以手动将项目添加回列表中。 但您也可以迭代无法以这种方式操作的对象。
如果你想使用 python 来实现该算法,你必须选择一个允许你想要使用的操作的数据结构。 我建议使用
.push()
和.pop()
方法,它们可以让您将列表视为堆栈。There is no way general way to push a value into an iterator in python. A stack or linked list is better suited to that.
If you're iterating over a list or something, of course you can add the item manually back to the list. But you can also iterate over objects which can't be manipulated in such a way.
If you want to use python to implement that algorithm, you'll have to choose a data structure that allows the operations you want to use. I suggest the
.push()
and.pop()
methods which let you treat lists as stacks.