【问题标题】:itertools.islice compared to list sliceitertools.islice 与列表切片相比
【发布时间】:2010-04-29 14:25:55
【问题描述】:

我一直在尝试应用一种算法来根据特定标准将 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,执行是即时的。

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

干杯, 忒弥斯

【问题讨论】:

  • vec.count("F", i, i+ratio) 代替sum( 1 for x in vec[i:i+ratio] if x == 'F' ) 怎么样?在我看来,它更具可读性并且可能更快。

标签: python performance iteration


【解决方案1】:

islice 适用于任意迭代。为此,它必须遍历第一个 n-1 元素,而不是直接跳到第 n 个元素,将它们扔掉,然后产生你想要的元素。

查看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 来抽象出连续的切片,发现这段代码比原来的代码更容易阅读

【讨论】:

  • grouper 确实是一个方便的功能,让事情更具可读性
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2015-11-17
    • 2022-11-01
    • 2013-11-30
    • 2020-07-16
    • 2016-03-22
    • 2011-10-24
    • 2021-09-07
    • 1970-01-01
    • 2010-12-14
    相关资源
    最近更新 更多