2024-05-17 05:06:08 发布
网友
我正在读Python,我想做一个关于列表理解的问题。问题很简单:
Write a Program that gives the sum of the multiples of 3 and 5 before some n take n = 1000 (Euler project, 1st problem)
我想这样做:
只有一行。。。但这行不通。在
1-这可以通过列表理解来实现?怎样??在
2-还有,什么时候使用列表理解是好的?在
谢谢!在
你快到了!试试这个:
mysum = sum([i for i in range(2,10) if i%2==0 or i%5==0])
这将在“循环”之外创建一个列表,然后将该列表传递给sum函数。在
sum
像mylist = [*some expression using i* for i in iterable]这样的列表理解是
mylist = [*some expression using i* for i in iterable]
像mylist = [*some expression using i* for i in iterable if *boolean with i*]这样的列表理解是
mylist = [*some expression using i* for i in iterable if *boolean with i*]
mylist = [] for i in iterable: if *boolean with i*: mylist.append(*some expression using i*)
当您需要使用某个表达式构造一个新的列表时,您可以使用它们。列表理解实际上比等价的for循环更有效,因为它们在底层的C中执行代码,而不是通过解释的python。在
for
C
列表理解的要点是生成一个结果值列表,每个源值一个(或者每个匹配源值的一个,如果您有if子句)。在
if
换言之,它与map(或者是map和{}调用链,如果有多个子句的话),只是可以将每个新值描述为旧值的表达式,而不必将其包装在函数中。在
map
你不能把一个语句(比如mysum = mysum + i)放入理解中,而只能放在表达式中。而且,即使你能想出一个有你想要的副作用的表达,那仍然是一个令人困惑的误用理解。如果不需要结果值的列表,则不要使用列表理解。在
mysum = mysum + i
如果您只是尝试在循环中执行计算,请编写一个显式的for循环。在
如果您真的需要它是一行,您可以随时这样做:
for i in [i for i in range(2, 10) if i%2==0 or i%5==0]: mysum += i
构建一个清单,用一个理解循环;在for循环中计算副作用y。在
(当然,这是假设您已经在mysum中添加了一些值,例如,使用mysum = 0。)
mysum
mysum = 0
而且,一般来说,当你想要一个仅仅循环一次的理解时,你想要的理解是一个生成器表达式,而不是一个列表理解。所以,把这些方括号变成括号,你会得到:
不过,不管怎样,这两行文字更具可读性和Python风格:
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有一个reduce函数。然而,仅仅使用它来消除for循环并将块语句转换为一个行程序,通常不被认为是Pythonic。在
reduce
fold
更一般地说,在Python中,试图把东西塞进一行通常会使内容的可读性降低,而不是更多,这通常意味着您需要键入更多的字符和要处理的标记,这远远抵消了节省行所带来的任何收益。在
当然,在这个特定的例子中,您真正想做的就是将一个列表的值求和。而这正是sum所做的。这很难理解。所以:
mysum += sum(i for i in range(2, 10) if i%2==0 or i%5==0)
(同样,这是假设您已经在mysum中有要添加的内容。如果不是,只需将+=改为=。后面的例子也是如此,所以我不再解释了。)
+=
=
尽管如此,我可能会将其写为显式嵌套块:
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) mysum += sum(not2to5)
以这种方式拆分代码是没有代价的(只要使用生成器表达式而不是列表理解),而且它通常会使代码的意图更加明显。在
有关生成器表达式的进一步解释:
生成器表达式与列表理解类似,只是它构建迭代器而不是列表。在某些函数式语言中只能使用“一次迭代”。(通常,这不是问题。在上面所有的例子中,我们唯一要做的就是将它传递给sum函数或在for循环中使用它,然后我们就再也不会引用它了。)当您迭代它时,每个值都是按需构造的,然后在到达下一个值之前释放。在
这意味着空间复杂度是恒定的,而不是线性的。你一次只能在内存中有一个值,而在一个列表中,你显然已经得到了所有的值。这通常是一个巨大的胜利。在
然而,时间复杂度不变。列表理解预先完成了所有的工作,所以它是线性时间来构建,然后免费使用。生成器表达式在您迭代它时执行工作,因此它是free构建,然后线性使用。不管怎样,同一时间。(实际上,由于缓存/内存局部性、流水线等原因,生成器表达式实际上可以快得多,更不用说避免了所有内存移动和分配开销。另一方面,对于一般情况,它的速度较慢,至少在CPython中是这样,因为它必须通过完整的迭代器协议,而不是列表的快速特殊大小写。)
(我在这里假设每一步的功是常数,显然[sum(range(i)) for i in range(n)]是n的二次方的,不是线性的…)
[sum(range(i)) for i in range(n)]
下面是我的两行实现,包括filter、sum和reduce:
def f(x): return x%3 == 0 or x%5 == 0 print sum(filter(f,range(2,1000)))
不错吧?你能给我解释一下这个代码:
你快到了!试试这个:
这将在“循环”之外创建一个列表,然后将该列表传递给
sum
函数。在像
^{pr2}$mylist = [*some expression using i* for i in iterable]
这样的列表理解是像
mylist = [*some expression using i* for i in iterable if *boolean with i*]
这样的列表理解是当您需要使用某个表达式构造一个新的列表时,您可以使用它们。列表理解实际上比等价的
for
循环更有效,因为它们在底层的C
中执行代码,而不是通过解释的python。在列表理解的要点是生成一个结果值列表,每个源值一个(或者每个匹配源值的一个,如果您有
if
子句)。在换言之,它与}调用链,如果有多个子句的话),只是可以将每个新值描述为旧值的表达式,而不必将其包装在函数中。在
map
(或者是map
和{你不能把一个语句(比如
mysum = mysum + i
)放入理解中,而只能放在表达式中。而且,即使你能想出一个有你想要的副作用的表达,那仍然是一个令人困惑的误用理解。如果不需要结果值的列表,则不要使用列表理解。在如果您只是尝试在循环中执行计算,请编写一个显式的
for
循环。在如果您真的需要它是一行,您可以随时这样做:
构建一个清单,用一个理解循环;在
for
循环中计算副作用y。在(当然,这是假设您已经在
mysum
中添加了一些值,例如,使用mysum = 0
。)而且,一般来说,当你想要一个仅仅循环一次的理解时,你想要的理解是一个生成器表达式,而不是一个列表理解。所以,把这些方括号变成括号,你会得到:
^{pr2}$不过,不管怎样,这两行文字更具可读性和Python风格:
…甚至三个:
如果您的语言使
reduce
/fold
比循环更直观,那么Python有一个reduce
函数。然而,仅仅使用它来消除for
循环并将块语句转换为一个行程序,通常不被认为是Pythonic。在更一般地说,在Python中,试图把东西塞进一行通常会使内容的可读性降低,而不是更多,这通常意味着您需要键入更多的字符和要处理的标记,这远远抵消了节省行所带来的任何收益。在
当然,在这个特定的例子中,您真正想做的就是将一个列表的值求和。而这正是
sum
所做的。这很难理解。所以:(同样,这是假设您已经在
mysum
中有要添加的内容。如果不是,只需将+=
改为=
。后面的例子也是如此,所以我不再解释了。)尽管如此,我可能会将其写为显式嵌套块:
…或作为迭代器转换的序列(在本例中实际上只是一个转换):
以这种方式拆分代码是没有代价的(只要使用生成器表达式而不是列表理解),而且它通常会使代码的意图更加明显。在
有关生成器表达式的进一步解释:
生成器表达式与列表理解类似,只是它构建迭代器而不是列表。在某些函数式语言中只能使用“一次迭代”。(通常,这不是问题。在上面所有的例子中,我们唯一要做的就是将它传递给
sum
函数或在for
循环中使用它,然后我们就再也不会引用它了。)当您迭代它时,每个值都是按需构造的,然后在到达下一个值之前释放。在这意味着空间复杂度是恒定的,而不是线性的。你一次只能在内存中有一个值,而在一个列表中,你显然已经得到了所有的值。这通常是一个巨大的胜利。在
然而,时间复杂度不变。列表理解预先完成了所有的工作,所以它是线性时间来构建,然后免费使用。生成器表达式在您迭代它时执行工作,因此它是free构建,然后线性使用。不管怎样,同一时间。(实际上,由于缓存/内存局部性、流水线等原因,生成器表达式实际上可以快得多,更不用说避免了所有内存移动和分配开销。另一方面,对于一般情况,它的速度较慢,至少在CPython中是这样,因为它必须通过完整的迭代器协议,而不是列表的快速特殊大小写。)
(我在这里假设每一步的功是常数,显然
[sum(range(i)) for i in range(n)]
是n的二次方的,不是线性的…)下面是我的两行实现,包括filter、sum和reduce:
不错吧?你能给我解释一下这个代码:
^{pr2}$相关问题 更多 >
编程相关推荐