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

niknxzdl  于 2023-04-10  发布在  Python
关注(0)|答案(6)|浏览(107)

因此,我想知道如何使用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]

我正在寻找一个有效的解决方案比什么都重要。我知道有很多方法可以做到这一点,但这不是我的问题。效率是。此外,这个操作将不得不做很多次,列表都将得到指数级的小。我没有一个方程来表示随着时间的推移,他们会得到多少小。
编辑:
数字必须在整个列表中保持排序,或者在索引被移除后恢复排序。索引列表可以是排序的,也可以不排序。它甚至不必在列表中。

vsaztqbk

vsaztqbk1#

为了提高效率,您可能需要考虑使用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
保持主数组不变,但维护一个掩码数组(虽然还没有做过任何速度测试……)也是值得考虑的。

9o685dep

9o685dep2#

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

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
zpqajqem

zpqajqem3#

另一个选择:

>>> 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]

编辑:

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

水平轴是项目的数量,垂直轴是以秒为单位的时间。
最快的选择是使用切片来构建一个新列表(来自@gnibbler):

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

令人惊讶的是,它和“sets”(@Eric)击败了numpy.delete(@Jon Clements)
这里是the script I used,也许我错过了什么。

brgchamk

brgchamk4#

这是我的第一个方法。

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布拉德利解决方案花的时间比我愿意等待的时间要长。)

编辑:这样稍微快一点:(0.55秒)

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

wztqucjr5#

不是那么有效率,而是一种不同的方法

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

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

jtjikinw6#

另一种不同的方法来实现这一点:

>>> 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]

相关问题