我对来自http://docs.python.org/2/library/itertools.html#itertools.imap的陈述感到好奇,即它描述了
sum(imap(operator.mul, vector1, vector2))
作为有效的点积。我的理解是imap给出了一个生成器而不是一个列表,虽然我理解如果你只考虑前几个元素,周围的sum(),它会更快/消耗更少的内存,我不知道如何它的表现与以下不同:
sum(map(operator.mul, vector1, vector2))
答案 0 :(得分:17)
当您开始增加迭代次数时,map
和imap
之间的区别变得清晰:
# xrange object, takes up no memory
data = xrange(1000000000)
# Tries to builds a list of 1 billion elements!
# Therefore, fails with MemoryError on 32-bit systems.
doubled = map(lambda x: x * 2, data)
# Generator object that lazily doubles each item as it's iterated over.
# Takes up very little (and constant, independent of data's size) memory.
iter_doubled = itertools.imap(lambda x: x * 2, data)
# This is where the iteration and the doubling happen.
# Again, since no list is created, this doesn't run you out of memory.
sum(iter_doubled)
# (The result is 999999999000000000L, if you're interested.
# It takes a minute or two to compute, but consumes minimal memory.)
请注意,在Python 3中,内置map
的行为类似于Python 2的itertools.imap
(因为不再需要它而被删除)。要获得“旧的map
”行为,您需要使用list(map(...))
,这是另一种可视化Python 2的itertools.imap
和map
彼此不同的好方法。< / p>
答案 1 :(得分:7)
第一行将逐个计算累计项目的总和。第二个将首先计算整个点积,然后,将整个结果存储在内存中,它将继续计算总和。因此存在内存复杂性增益。
答案 2 :(得分:3)
另外需要注意的是“使用更少的内存”通常意味着“运行速度更快”。惰性(迭代器)版本在计算后立即使用每个产品,并将其添加到运行总和中。产品和运行总和几乎肯定都在L1缓存中。如果你首先计算所有产品,那么根据元素的数量,确定计算出的第一批产品将从L1缓存中踢出,然后从L2缓存中取出,并且...当第二次传递时最后将它们加在一起,所有产品在内存层次结构中都很低(而且极端情况下,必须从分页文件中读取)。
但我不清楚你的意思是“不要看它的表现如何与”不同。最终的计算结果都是相同的。
答案 3 :(得分:2)
不同之处在于imap(...)
或map(...)
的整个输出都会传递给sum()
。你写的是imap
返回一个生成器,但我认为你可能会认为sum(map(...))
有一些做同样事情的快捷方式。它没有。在将任何内容传递给map()
之前,sum()
将构建一个完整的结果列表。