我一直在尝试应用一种算法,根据特定条件将 Python 列表缩减为更小的列表。由于原始列表的体积很大,大约有 100k 个元素,我尝试使用 itertools 来避免多次内存分配,所以我想出了这个:
reducedVec = [ 'F' if sum( 1 for x in islice(vec, i, i+ratio) if x == 'F' )
> ratio / 3.0 else 'T'
for i in xrange(0, len(vec), ratio) ]
当 vec 有大约 100k 个元素时,这个执行时间需要几分钟的时间,令人担忧。当我改为尝试时:
reducedVec = [ 'F' if sum( 1 for x in vec[i:i+ratio] if x == 'F' )
> ratio / 3.0 else 'T'
for i in xrange(0, len(vec), ratio) ]
本质上用切片替换 islice,执行是即时的。
你能想出一个合理的解释吗?我原以为避免重复分配一个包含大量元素的新列表,实际上会节省我几个计算周期,而不是削弱整个执行。
干杯, 忒弥斯
最佳答案
islice
适用于任意可迭代对象。为此,它不是直接跳到第 n 个元素,而是必须遍历前 n-1 个元素,将它们扔掉,然后产生你想要的元素。
从 itertools documentation 查看纯 Python 实现:
def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
nexti = next(it)
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
说到 itertools 文档,如果我尝试执行此操作,我可能会使用 grouper
配方。它实际上不会为您节省任何内存,但如果您将其重写为更懒惰,它可以,这并不难。
from __future__ import division
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
reducedVec = []
for chunk in grouper(ratio, vec):
if sum(1 for x in chunk if x == 'F') > ratio / 3:
reducedVec.append('F')
else:
reducedVec.append('T')
我喜欢使用 grouper
来抽象出连续的切片,并且发现这段代码比原来的代码更容易阅读
关于python - itertools.islice 与列表切片相比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2738096/