本文介绍了python中的列表理解,如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读有关Python的内容,我想在列表理解方面做一个问题.问题很简单:

I am reading about Python and I want to do a problem with list comprehensions. The problem is simple:

取n = 1000(Euler项目,第一个问题)

Take n = 1000 (Euler project, 1st problem)

我想做这样的事情:

[mysum = mysum + i for i in range(2,1000) if i%3==0 or i%5==0]

只有一行...但这不起作用.

With only one line... But that does not work.

  1. 这可以通过列表理解来实现吗?如何??
  2. 此外,什么时候可以使用列表推导?

推荐答案

列表理解的重点是生成结果值列表,每个源值一个(或每个匹配源值一个,如果您有 if 子句).

The point of list comprehensions is to generate a list of result values, one per source value (or one per matching source value, if you have if clauses).

换句话说,它与 map 是相同的(或者,如果您有多个子句,则是一系列的 map filter 调用),除了您可以根据旧值将每个新值描述为一个表达式,而不必将其包装在函数中.

In other words, it's the same thing as map (or a chain of map and filter calls, if you have multiple clauses), except that you can describe each new value as an expression in terms of the old value, instead of having to wrap that up in a function.

您不能将语句(例如 mysum = mysum + i )放入理解中,而只能放入表达式中.而且,即使您可以提出一个具有您想要的副作用的表达式,这仍然是对理解的一种令人困惑的误用.如果您不想要结果值列表,请不要使用列表推导.

You can't put a statement (like mysum = mysum + i) into a comprehension, only an expression. And, even if you can come up with an expression that has the side-effect you want, that would still be a confusing misuse of the comprehension. If you don't want a list of result values, don't use a list comprehension.

如果您只是想在一个循环中执行计算,请编写一个显式的 for 循环.

If you're just trying to perform a computation in a loop, write an explicit for loop.

如果您确实需要将其设为一行,则可以始终执行以下操作:

If you really need it to be one line, you can always do this:

for i in [i for i in range(2, 10) if i%2==0 or i%5==0]: mysum += i

建立一个理解的清单.在 for 循环中进行副作用计算.

Build the list of things to loop over with a comprehension; do the side-effect-y calculation in a for loop.

(当然,前提是您已经在 mysum 中添加了一些值,例如,使用 mysum = 0 .)

(Of course that's assuming you've already got some value in mysum to add on to, e.g., using mysum = 0.)

通常,每当您想要一次仅用于一次循环的理解时,您想要的那种理解就是生成器表达式,而不是列表理解.因此,将那些方括号变成括号,即可得到:

And, in general, whenever you want a comprehension just for looping over once, the kind of comprehension you want is a generator expression, not a list comprehension. So, turn those square brackets into parentheses, and you get this:

for i in (i for i in range(2, 10) if i%2==0 or i%5==0): mysum += i

不过,无论哪种方式,它在两行代码中都更具可读性和Pythonic:

Either way, though, it's more readable and pythonic as two lines:

for i in (i for i in range(2, 10) if i%2==0 or i%5==0):
    mysum += i

…甚至三个:

not2or5 = (i for i in range(2, 10) if i%2==0 or i%5==0)
for i in not2or5:
    mysum += i


如果您使用的语言比循环更直观地使 reduce / fold 比Python更直观,则Python具有 reduce 函数.但是,通常不认为仅使用Pythonic来消除 for 循环并将块语句转换为单行代码即可.


If you're coming from a language that makes reduce/fold more intuitive to you than loops, Python has a reduce function. However, it's generally not considered Pythonic to use it just to eliminate for loops and turn block statements into one-liners.

更一般而言,尝试将内容塞入一行通常会使内容在Python中的可读性下降,而不是更多,并且通常意味着您最终需要输入更多字符并在头脑中处理更多令牌,这远远超过了取消操作的目的.节省了更多的钱.

More generally, trying to cram things into a single line usually makes things less readable, not more, in Python, and often means you end up with more characters to type and more tokens to process in your head, which more than cancels out any gain in saving lines.

当然,在这种情况下,您真正​​想要做的就是总结列表的值.而这正是 sum 的作用.这很容易理解.所以:

Of course in this specific case, all you really want to do is sum up the values of a list. And that's exactly what sum does. And that's trivial to understand. So:

mysum += sum(i for i in range(2, 10) if i%2==0 or i%5==0)

(同样,假设您已经在 mysum 中添加了一些内容.如果没有,只需将 + = 更改为 = .以后的所有示例也是如此,因此,我将不再对其进行解释.)

(Again, this is assuming you already have something in mysum you want to add onto. If not, just change the += to an =. The same is true for all of the later examples, so I'll stop explaining it.)

话虽如此,我可能会将其写为一个显式的嵌套块:

All that being said, I'd probably write this either as an explicit nested block:

for i in range(2, 10):
    if i%2==0 or i%5==0:
        mysum += i

…或作为一系列迭代器转换(在这种情况下,实际上只是一个转换):

… or as a sequence of iterator transformations (which in this case is really just one transformation):

not2or5 = (i for i in range(2, 10) if i%2==0 or i%5==0)
mysum += sum(not2to5)

以这种方式进行拆分实际上并没有成本(只要您使用生成器表达式而不是列表推导),通常这会使代码的意图更加明显.

There's really no cost to splitting things up this way (as long as you use generator expressions instead of list comprehensions), and it usually makes the intent of your code a lot more obvious.

有关生成器表达式的进一步说明:

Some further explanation on generator expressions:

生成器表达式类似于列表推导,不同之处在于它生成迭代器而不是列表.在某些功能语言中,迭代器类似于惰性列表",不同之处在于,迭代器只能使用一次.(通常,这不是问题.在以上所有示例中,我们要做的唯一一件事就是将其传递给 sum 函数或在 for 循环中使用它,然后我们再也不会引用它了.)当您遍历它时,每个值都是按需构造的,然后在到达下一个值之前将其释放.

A generator expression is just like a list comprehension, except that it builds an iterator instead of a list. An iterator is similar to a "lazy list" in some functional languages, except that you can only use it once. (Usually, that's not a problem. In all the examples above, the only thing we want to do is pass it to the sum function or use it in a for loop, and then we never refer to it again.) As you iterate over it, each value is constructed on demand, and then freed before you get to the next one.

这意味着空间复杂度是恒定的,而不是线性的.您一次只能在内存中获得一个值,而对于一个列表,您显然拥有所有这些值.这通常是一个巨大的胜利.

This means the space complexity is constant, instead of linear. You've only ever got one value in memory at a time, whereas with a list you've obviously got all of them. That's often a huge win.

但是,时间复杂度没有变化.列表推导会预先完成所有工作,因此构建是线性的时间,然后可以自由使用.生成器表达式可以在您对其进行迭代时完成工作,因此可以自由构建,然后线性使用.无论哪种方式,都是同一时间.(实际上,由于高速缓存/内存位置,流水线等原因,生成器表达式实际上可以显着更快地运行,更不用说避免了所有内存移动和分配成本.另一方面,对于琐碎的情况,它至少要慢一些.CPython,因为它必须通过完整的迭代器协议,而不是用于列表的快速特殊包装.)

However, the time complexity is unchanged. A list comprehension does all the work up front, so it's linear time to build, then free to use. A generator expression does the work as you iterate over it, so it's free to build, then linear to use. Either way, same time. (A generator expression can actually be significantly faster in practice, because of cache/memory locality, pipelining, etc., not to mention avoiding all the memory moving and allocation costs. On the other hand, it's slower for trivial cases, at least in CPython, because it has to go through the full iterator protocol instead of the quick special-casing for lists.)

(我在这里假设每个步骤的工作是恒定的,显然 [在range(n)中i的sum [range(i))] 在n中是平方的,不是线性的…)

(I'm assuming here that the work for each step is constant—obviously [sum(range(i)) for i in range(n)] is quadratic in n, not linear…)

这篇关于python中的列表理解,如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 09:44