【发布时间】:2012-07-03 10:20:55
【问题描述】:
假设我在这里有这个清单:
list = [a, b, c, d, e, f, g]
如何同时删除说索引2, 3, 4 和5?
pop 不接受多个值。我该怎么做?
【问题讨论】:
假设我在这里有这个清单:
list = [a, b, c, d, e, f, g]
如何同时删除说索引2, 3, 4 和5?
pop 不接受多个值。我该怎么做?
【问题讨论】:
对于不同方式的性能没有太多提示,所以我进行了测试,以所有 3 种通常不同的方法从 50000 中删除 5000 项,对我来说,numpy 是赢家(如果你有适合 numpy 的元素) :
这是我计时的代码(如果可以直接处理 numpy 数组,则可以删除从/到列表的第三个函数转换):
import time
import numpy as np
import random
def del_list_indexes(l, id_to_del):
somelist = [i for j, i in enumerate(l) if j not in id_to_del]
return somelist
def del_list_inplace(l, id_to_del):
for i in sorted(id_to_del, reverse=True):
del(l[i])
def del_list_numpy(l, id_to_del):
arr = np.array(l, dtype='int32')
return list(np.delete(arr, id_to_del))
l = range(50000)
random.shuffle(l)
remove_id = random.sample(range(len(l)), 5000) # 10% ==> 5000
# ...
【讨论】:
del_list_indexes 如果先将id_to_del 转换为集合,应该会快得多。
set 用于enumerate,我得到的时间是:enumerate = 0.0041、del = 0.035、numpy = 0.0079,已枚举为预期的最快。
另一个选项(就地,任何索引组合):
_marker = object()
for i in indices:
my_list[i] = _marker # marked for deletion
obj[:] = [v for v in my_list if v is not _marker]
【讨论】:
lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
lst = lst[0:2] + lst[6:]
这是一个单步操作。它不使用循环,因此执行速度很快。它使用列表切片。
【讨论】:
lst 作为变量名,因为 list 是 Python 数据类型。没有人建议将此作为解决方案的原因是,这会创建一个新的列表对象(基于原始列表对象),而不是实际修改原始列表对象。由于最终结果是相似的,我会赞成你的答案。欢迎来到Stack Exchange。
老问题,但我有答案。
首先,像这样细读列表中的元素:
for x in range(len(yourlist)):
print '%s: %s' % (x, yourlist[x])
然后,使用您要弹出的元素的索引列表调用此函数。它足够健壮,列表的顺序无关紧要。
def multipop(yourlist, itemstopop):
result = []
itemstopop.sort()
itemstopop = itemstopop[::-1]
for x in itemstopop:
result.append(yourlist.pop(x))
return result
作为奖励,结果应该只包含您想要删除的元素。
在 [73] 中:mylist = ['a','b','c','d','charles']
在 [76] 中:对于范围内的 x(len(mylist)):
mylist[x])....:
0: 一个
1: b
2:c
3: d
4: 查尔斯
...
在 [77] 中:multipop(mylist, [0, 2, 4])
输出[77]: ['charles', 'c', 'a']
...
在 [78] 中:我的列表
输出[78]: ['b', 'd']
【讨论】:
如果你可以使用numpy,那么你可以删除多个索引:
>>> import numpy as np
>>> a = np.arange(10)
>>> np.delete(a,(1,3,5))
array([0, 2, 4, 6, 7, 8, 9])
如果您使用np.r_,您可以将切片与单个索引结合起来:
>>> np.delete(a,(np.r_[0:5,7,9]))
array([5, 6, 8])
但是,删除的不是in place,所以你要给它赋值。
【讨论】:
如果它们是连续的,你可以这样做
x[2:6] = []
如果要删除不连续的索引,那就有点棘手了。
x = [v for i,v in enumerate(x) if i not in frozenset((2,3,4,5))]
【讨论】:
remove_indices = [1,2,3]
somelist = [i for j, i in enumerate(somelist) if j not in remove_indices]
例子:
In [9]: remove_indices = [1,2,3]
In [10]: somelist = range(10)
In [11]: somelist = [i for j, i in enumerate(somelist) if j not in remove_indices]
In [12]: somelist
Out[12]: [0, 4, 5, 6, 7, 8, 9]
【讨论】:
remove_indices 转换为set!
您需要循环执行此操作,没有内置操作可以一次删除多个索引。
您的示例实际上是一个连续的索引序列,因此您可以这样做:
del my_list[2:6]
删除从 2 开始并在 6 之前结束的切片。
从您的问题中不清楚您通常是否需要删除任意索引集合,或者它是否始终是一个连续的序列。
如果您有任意索引集合,则:
indexes = [2, 3, 5]
for index in sorted(indexes, reverse=True):
del my_list[index]
注意,你需要以相反的顺序删除它们,这样你就不会丢掉后面的索引。
【讨论】:
my_list.pop(index) 而不是del my_list[index],这会有什么不同?有关系吗?在效率还是语义方面?
del,尽管两者都可以。