打破清单理解

Fla*_*ius 52 python list-comprehension

如何根据条件中断列表理解,例如何时412找到数字?

码:

numbers = [951, 402, 984, 651, 360, 69, 408, 319, 601, 485, 980, 507, 725, 547, 544,
           615, 83, 165, 141, 501, 263, 617, 865, 575, 219, 390, 984, 592, 236, 105, 942, 941,
           386, 462, 47, 418, 907, 344, 236, 375, 823, 566, 597, 978, 328, 615, 953, 345, 399,
           162, 758, 219, 918, 237, 412, 566, 826, 248, 866, 950, 626, 949, 687, 217, 815, 67,
           104, 58, 512, 24, 892, 894, 767, 553, 81, 379, 843, 831, 445, 742, 717, 958, 609, 842,
           451, 688, 753, 854, 685, 93, 857, 440, 380, 126, 721, 328, 753, 470, 743, 527]

even = [n for n in numbers if 0 == n % 2]
Run Code Online (Sandbox Code Playgroud)

所以在功能上,你可以推断这应该做的事情:

even = [n for n in numbers if 0 == n % 2 and break if n == 412]
Run Code Online (Sandbox Code Playgroud)

真的更喜欢:

  • 单行
  • 没有其他花哨的库,如itertools,"纯python",如果可能的话(读:解决方案不应该使用任何import语句或类似)

Rei*_*ica 53

使用函数来引发StopIterationlist捕获它:

>>> 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]
Run Code Online (Sandbox Code Playgroud)

对于那些抱怨它不是一个单行:

even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)
Run Code Online (Sandbox Code Playgroud)

对于那些抱怨的人来说,它是hackish,不应该用在生产代码中:嗯,你是对的.当然.

  • 或者对于单行代码,将`end_of_loop()`替换为`next(iter([]))`. (13认同)
  • `运行时错误:生成器引发 StopIteration` (10认同)
  • @FJ是的,我在你的评论前几​​分钟更新了我的答案. (4认同)
  • 有趣的伎俩!并不是说我会在实际代码中使用它,但无论如何它都是一个很好的观察. (2认同)
  • 在 Python 3+ 中是否有一个完全可行的修复? (2认同)
  • @Zuza PEP的[“破例示例”](https://www.python.org/dev/peps/pep-0479/#examples-of-breakage)部分中包含一个非常相似的示例。您可以在末尾找到它。单行解决方法将不再可行-您需要定义一个生成器函数。 (2认同)

Sve*_*ach 43

您可以将生成器表达式与itertools.takewhile():

even_numbers = (n for n in numbers if not n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))
Run Code Online (Sandbox Code Playgroud)

编辑:我刚刚注意到要求不使用任何imports.好吧,无论如何,我在这里留下这个答案.

  • 如果他真的想要他的一个班轮:`[n在itertools.take中为n(lambda x:x!= 412,数字),如果不是n%2] (9认同)

And*_*ark 14

如果412肯定会在列表中,你可以使用这个:

even = [n for n in numbers[:numbers.index(412)] if not n % 2]
Run Code Online (Sandbox Code Playgroud)

如果要在结果中包含412,则仅numbers[:numbers.index(412)+1]用于切片.

请注意,由于切片,这将比itertools或for循环解决方案效率低(至少在内存方面).

  • @FelixKling:412的线性搜索是超快的C代码,而其他解决方案在Python代码中测试412,一些解决方案调用函数(在CPython中很昂贵)*每个数字*.我相信这个解决方案更快! - 列表副本也以非常快的C代码完成; 除非你内存紧张,否则应该没有性能问题.(好吧,如果第一个数字是412并且列表有10**6个条目,那就不好了;但如果412是最后一个数字,那么这个解决方案应该仍然非常非常快.) (4认同)
  • @FelixKling - 然而,在快速的时间测试中,其他答案显示,这对于提供的样本数据来说更快.我绝对希望其他人在数据集增加时通过它. (2认同)

Mic*_*son 14

even = [n for n in numbers[:None if 412 not in numbers else numbers.index(412)] if not n % 2] 
Run Code Online (Sandbox Code Playgroud)

刚刚上面的FJ代码并添加了一个三元组来检查412是否在列表中.仍然是"一个班轮",即使412不在列表中也能工作.

  • 谁是FJ,"上面的代码"在哪里?不要将Stack Overflow误认为(传统)*论坛*; 根据[巡演],答案可能会升至顶部或降至最低点. (5认同)
  • @ usr2564301。我会牢记这一点。当我在 **6 年前**回答这个问题时,一定有另一个我改进的答案被评为高于此。 (5认同)
  • 感谢所有为本文提供建议的人。然而,这种做法只会让那些不太熟练的人在 12 个月后试图理解这一点时感到沮丧。我们能否避免“一句话”导致“一小时”尝试解码它们? (3认同)

Ani*_*l_M 14

我知道这是一篇非常古老的帖子,但是由于OP询问break内部使用list-comprehension,我也在寻找类似的东西,我想我会在这里发布我的发现以供将来参考.

在调查break时,我看到鲜为人知的特性来了iter作为iter(callable, sentinel)其返回一个迭代器,"休息"迭代一次赎回function价值等于sentinel价值.

>>> 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.
Run Code Online (Sandbox Code Playgroud)

这里棘手的部分是定义一个适合给定问题的函数.在这种情况下,我们首先需要转换给定listnumbers一个来iterator使用x = iter(numbers)外部变量成饲料lambda的功能.

接下来,我们的可调用函数只是调用迭代器来吐出下一个值.然后迭代器与我们的标记值(在这种情况下为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]
Run Code Online (Sandbox Code Playgroud)

  • 避免 lambda 并使其更短的修改是使用 `__next__`:`[i for i in iter(iter(numbers).__next__, 412) if i%2 == 0]`。然而,虽然还不清楚,但最初的问题意味着只有偶数会根据哨兵进行检查,因此我们可以使这个更简单:`list(iter((i for i in Numbers if i%2 == 0).__next__, 412))`。 (4认同)