所以我想知道如何使用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的列表可以排序也可以不排序。它甚至不必在列表中。
答案 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.delete
:http://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]
修改强>
因此,在对这个答案毫无绝对错误之后,我对每种不同的方法进行了基准测试:
水平轴是项目数,垂直是以秒为单位的时间。
最快的选择是使用切片来构建新列表(来自@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]