itertools.islice与列表sli比较

2024-06-07 18:52:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在尝试应用一种算法,根据特定的条件将python列表缩小为一个较小的列表。由于原始列表的容量很大,按10万个元素的顺序排列,我尝试使用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执行是即时的。

你能想出一个合理的解释吗?我本以为,避免重复分配一个包含大量元素的新列表,实际上可以节省一些计算周期,而不是破坏整个执行过程。

干杯, 主题


Tags: in算法元素列表forlenif条件
2条回答

我的猜测是,使用islice()涉及到对vec的每个元素的Python函数调用,而扩展切片表示法被解析器理解并直接转换为CPython调用。

islice使用任意iterable。要做到这一点,而不是直接跳到第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来提取连续的片段,并发现这段代码比原来的代码更容易阅读

相关问题 更多 >

    热门问题