从Python 2.7中的数字列表中删除一组索引的最有效方法是什么?

时间:2012-11-27 00:31:14

标签: python list indexing

所以我想知道如何使用Python 2.7,最有效地获取用于表示这样的索引的值列表:(但长度最多为250,000 +)

indices = [2, 4, 5]

并从更大的列表中删除索引列表,如下所示:(3,000,000多项)

numbers = [2, 6, 12, 20, 24, 40, 42, 51]

得到这样的结果:

[2, 6, 20, 42, 51]

我正在寻找一种有效的解决方案。我知道有很多方法可以做到这一点,但这不是我的问题。效率是。此外,此操作必须多次完成,列表将以指数方式变小。我没有一个等式来表示它们随着时间的推移会变小多少。

编辑:

数字必须在整个时间内保持在列表中排序,或者在删除索引后返回到排序。名为indices的列表可以排序也可以不排序。它甚至不必在列表中。

6 个答案:

答案 0 :(得分:6)

您可能需要考虑使用numpy库来提高效率(如果您处理整数列表可能不是一个坏主意):

>>> import numpy as np
>>> a = np.array([2, 6, 12, 20, 24, 40, 42, 51])
>>> np.delete(a, [2,4,5])
array([ 2,  6, 20, 42, 51])

关于np.deletehttp://docs.scipy.org/doc/numpy/reference/generated/numpy.delete.html

的说明

在保持主数组不变的情况下也可能值得,但保持一个蒙面数组(虽然没有对它进行过任何速度测试......)

答案 1 :(得分:5)

我怀疑在索引之间取整个切片可能比列表理解更快

def remove_indices(numbers, indices):
    result = []
    i=0
    for j in sorted(indices):
        result += numbers[i:j]
        i = j+1
    result += numbers[i:]
    return result

答案 2 :(得分:3)

这是我的第一个方法。

def remove_indices(numbers, indices):
    indices = set(indices)
    return [x for i, x in enumerate(numbers) if i not in indices]

这是一个测试模块,可以在您指定的条件下对其进行测试。 (300万元素,需要250k才能删除)

import random

def create_test_set():
    numbers = range(3000000)
    indices = random.sample(range(3000000), 250000)
    return numbers, indices

def remove_indices(numbers, indices):
    indices = set(indices)
    return [x for i, x in enumerate(numbers) if i not in indices]

if __name__ == '__main__':
    import time
    numbers, indices = create_test_set()
    a = time.time()
    numbers = remove_indices(numbers, indices)
    b = time.time()
    print b - a, len(numbers)

我的笔记本电脑需要大约0.6秒。如果您要多次使用索引,可以考虑事先设置索引。

(FWIW bradley.ayers解决方案花费的时间比我愿意等待的时间长。)

修改:这稍快一些:(0.55秒)

def remove_indices(numbers, indices):
    return [numbers[i] for i in xrange(len(numbers)) if i not in indices]

答案 3 :(得分:2)

另一种选择:

>>> numbers = [2, 6, 12, 20, 24, 40, 42, 51]
>>> indicies = [2, 4, 5]
>>> offset = 0
>>> for i in indicies:
...     del numbers[i - offset]
...     offset += 1
...
>>> numbers
[2, 6, 20, 42, 51]

修改

因此,在对这个答案毫无绝对错误之后,我对每种不同的方法进行了基准测试:

enter image description here

水平轴是项目数,垂直是以秒为单位的时间。

最快的选择是使用切片来构建新列表(来自@gnibbler):

def using_slices(numbers, indices):
    result = []
    i = 0
    for j in indices:
        result += numbers[i:j]
        i = j + 1
    result += numbers[i:]

令人惊讶的是它和“集合”(@Eric)击败numpy.delete(@Jon Clements)

这是the script I used,也许我错过了什么。

答案 4 :(得分:1)

效率不高,但方法不同

indices = set([2, 4, 5])

result = [x for i,x in enumerate(numbers) if i not in indices]

答案 5 :(得分:0)

实现这一目标的另一种不同方法:

>>> numbers = [2, 6, 12, 20, 24, 40, 42, 51]
>>> indices = [2, 4, 5]
>>> [item for item in numbers if numbers.index(item) not in indices]
[2, 6, 20, 42, 51]