Python 在列表理解中使用break
如何根据条件打破列表理解,例如当找到编号Python 在列表理解中使用break,python,list-comprehension,Python,List Comprehension,如何根据条件打破列表理解,例如当找到编号412时 代码: 所以从功能上来说,你可以推断这是应该做的: even = [n for n in numbers if 0 == n % 2 and break if n == 412] 我真的更喜欢: 一艘班轮 如果可能的话,没有其他像itertools这样的高级库,“纯python”(请阅读:解决方案不应使用任何import语句或类似语句) 如果412肯定会出现在列表中,您可以使用: even = [n for n in numbers[:num
412
时
代码:
所以从功能上来说,你可以推断这是应该做的:
even = [n for n in numbers if 0 == n % 2 and break if n == 412]
我真的更喜欢:
- 一艘班轮
- 如果可能的话,没有其他像itertools这样的高级库,“纯python”(请阅读:解决方案不应使用任何
语句或类似语句)import
even = [n for n in numbers[:numbers.index(412)] if not n % 2]
如果要在结果中包含412,只需对切片使用numbers[:numbers.index(412)+1]
请注意,由于切片的原因,这将比itertools或for循环解决方案的效率更低(至少在内存方面)。您可以将生成器表达式与itertools.takewhile()一起使用。:
Edit:我刚刚注意到不使用任何
import
s的要求。好吧,我还是把这个答案留在这里。使用一个函数来引发StopIteration
和list
来捕捉它:
>>> def end_of_loop():
... raise StopIteration
...
>>> even = list(end_of_loop() if n == 412 else n for n in numbers if 0 == n % 2)
>>> print(even)
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418, 344, 236, 566, 978, 328, 162, 758, 918]
对于那些抱怨的人来说,这不是一句简单的话:
even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)
对于那些抱怨它是黑客的,不应该在生产代码中使用:嗯,你是对的肯定。列表显示(包括列表理解)的语法如下: 如您所见,while或
直到
语法没有特殊的。你能得到的最接近的是:
even_numbers = (n for n in numbers if 0 == n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))
(代码取自斯文·马纳奇的答案,在我打字时发布)
只是在上面取了F.J.的代码,并添加了一个三元组来检查412是否在列表中。仍然是“一行”,即使412不在列表中也会起作用。我知道这是一篇非常古老的帖子,但是由于OP询问在列表理解中使用中断,并且我也在寻找类似的东西,我想我会在这里发布我的发现以供将来参考
在研究break
时,我发现iter
的一个鲜为人知的特性是iter(callable,sentinel)
,它返回一个迭代器,一旦可调用函数
值等于sentinel
值,它就会“break”迭代
>>> help(iter)
Help on built-in function iter in module __builtin__:
iter(...)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
这里棘手的部分是定义一个适合给定问题的函数。在这种情况下,我们首先需要使用x=iter(numbers)
将给定的列表
中的数字
转换为一个迭代器
,该迭代器作为外部变量输入lambda
函数
接下来,我们的可调用函数只是调用迭代器来输出下一个值。迭代器然后与我们的sentinel值(本例中为412)进行比较,并在达到该值后“中断”
print [i for i in iter(lambda x=iter(numbers): next(x),412) if i %2 == 0]
>>>
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418,
344, 236, 566, 978, 328, 162, 758, 918]
另一个利用结束
条件解决打断列表理解的狡猾的单行解决方案
如果不使用数字。索引(412)
,可能会快一点
even = [n for end in [[]] for n in numbers
if (False if end or n != 412 else end.append(42))
or not end and not n % 2]
注意:这是个坏主意。只是为了好玩:)
正如@WolframH所说:
对于那些抱怨它是黑客的,不应该在生产代码中使用:嗯,你是对的肯定。
考虑到发电机解决方案已经过时,我提出了以下建议:
even = [n for n in next((numbers[:i] for i, n in enumerate(numbers) if n == 412)) if not n % 2]
然后我回去看了安德鲁·克拉克的答案,答案是一样的,但要好得多
even = [n for n in numbers[:numbers.index(412)] if not n % 2]
不管怎样,切片解决方案的最佳部分是,您可以选择在结束元素的任一侧包含或排除多个元素,例如,获取412和后面的数字:
even = [n for n in numbers[:numbers.index(412)+2] if not n % 2]
itertools
是纯python<代码>itertools
是Python。。。总的来说,这听起来像是一个普通的for
循环的工作。@Flavius:为什么从Python自己的库中导入一些东西不“炫耀它的能力”?@Flavius:所以你试图说服你的同事,你可以用Python写一些粗俗难看的东西,这会给他们留下深刻印象?@Flavius,Python的强大之处在于它的标准库。如果内置更多的标准库函数,Python会“更强大”吗?我想不是。无论哪种方式,它们都是标准的,但如果它们是内置的,则命名空间冲突的可能性会更大。最好将它们分开。不仅因为切片效率较低,它还必须对列表进行线性搜索。@FelixKling-不过,在一次快速测试中,它与其他答案一起测试表明,对于提供的样本数据来说,这更快。不过,随着数据集的增加,我肯定会期望其他解决方案通过它。@FelixKling:412的线性搜索是超快速的C代码,而其他解决方案在Python代码中测试412,有些解决方案对每个数字都调用一个函数(在CPython中很昂贵)。我相信这个解决方案会更快列表复制也是用非常快的C代码完成的;除非内存紧张,否则不会出现性能问题。(好的,如果第一个数字是412,并且列表中有10**6个条目,这是不好的;但是如果412是最后一个数字,这个解决方案应该仍然非常非常快。)考虑到前面的评论,+1ed.有趣的技巧!并不是说我曾经在真实的代码中使用过它,但不管怎样,这是一个很好的观察结果。或者对于一行,用end\u of_loop()
替换为next(iter([])
@F.J是的,我在你发表评论前几分钟更新了我的答案。@Zuza一个非常类似的例子包含在政治公众人物部分中。你可以在最后找到它。单行解决方案将不再可行-您需要定义一个生成器函数。RuntimeError:generator引发了StopIteration
如果他真的想要一行:[itertools.takewhile(lambda x:x!=412,numbers)中的n代表n,如果不是n%2]
我没有投反对票,但我想这是因为你从别人那里拿走了密码。至少你承认了。如果412不在numbers
中,如果是偶数,最后一个元素将丢失。谁是F.J.“上面的代码”在哪里?别搞错了
even = [n for n in next((numbers[:i] for i, n in enumerate(numbers) if n == 412)) if not n % 2]
even = [n for n in numbers[:numbers.index(412)] if not n % 2]
even = [n for n in numbers[:numbers.index(412)+2] if not n % 2]