从列表中删除多个元素

是否可以同时从列表中删除多个元素? 如果我想删除索引0和2处的元素,并尝试像del somelist [0],其次是del somelist [2],则第二条语句实际上会删除somelist [3]。

我想我总是可以先删除更高编号的元素,但我希望有一个更好的方法。

可能不是这个问题的最佳解决scheme:

indices = 0, 2 somelist = [i for j, i in enumerate(somelist) if j not in indices] 

如果你删除多个不相邻的项目,那么你所描述的是最好的方法(是的,一定要从最高的索引开始)。

如果您的项目相邻,则可以使用切片分配语法:

 a[2:10] = [] 

出于某种原因,我不喜欢这里的任何答案。 是的,他们工作,但严格地说,他们大部分都不是删除列表中的元素,是吗? (但是制作一个副本,然后用编辑的副本replace原来的副本)。

为什么不直接删除更高的索引呢?

这是有原因吗? 我只会做:

 for i in sorted(indices, reverse=True): del somelist[i] 

如果你真的不想删除项目倒退,那么我想你应该删除大于最后删除的索引(不能真正使用相同的索引,因为你有一个不同的列表)的索引值或使用列表的副本(不会“删除”,而是用编辑后的副本replace原件)。

我在这里错过了什么,有什么理由不以相反的顺序删除?

作为一个function:

 def multi_delete(list_, *args): indexes = sorted(list(args), reverse=True) for index in indexes: del list_[index] return list_ 

运行n log(n)时间,这应该是最快的正确解决scheme了。

作为Greg的答案的专业化,你甚至可以使用扩展的片语法。 例如。 如果你想删除项目0和2:

 >>> a= [0, 1, 2, 3, 4] >>> del a[0:3:2] >>> a [1, 3, 4] 

这当然不包括任意的select,但它当然可以用于删除任何两个项目。

那么,你基本上想要在一次传递中删除多个元素? 在这种情况下,要删除的下一个元素的位置将被先前删除的许多位置所抵消。

我们的目标是删除预先计算为索引1,4和7的所有元音。请注意,其重要的to_delete索引是按升序排列,否则将不起作用。

 to_delete = [1, 4, 7] target = list("hello world") for offset, index in enumerate(to_delete): index -= offset del target[index] 

如果你想以任何顺序删除元素,这将是一个更复杂的。 国际海事组织,sortingto_delete可能比找出什么时候你应该或不应该从index减去容易。

你可以使用numpy.delete如下:

 import numpy as np a = ['a', 'l', 3.14, 42, 'u'] I = [0, 2] np.delete(a, I).tolist() # Returns: ['l', '42', 'u'] 

如果你不介意在最后得到一个numpy数组,你可以.tolist() 。 您也应该看到一些非常重要的速度改进,使其成为一个更具可扩展性的解决scheme。 我没有对它进行基准testing,但是numpy操作是用C或Fortran编写的编译代码。

我是Python的初学者,目前我的编程是粗糙而肮脏的,但我的解决scheme是使用早期教程中学到的基本命令的组合:

 SomeList = [1,2,3,4,5,6,7,8,10] Rem = [0,5,7] for i in Rem: SomeList[i]='!' # mark for deletion for i in range(0,SomeList.count('!')): SomeList.remove('!') # remove print SomeList 

显然,由于不得不select“删除标记”字符,这是有其局限性的。

至于性能作为列表尺寸的大小,我敢肯定,我的解决scheme是次优的。 然而,它很简单,我希望吸引其他初学者,并将在SomeList是一个众所周知的格式,例如,总是数字的简单情况下工作…

这是一个替代scheme,它不使用枚举()来创build元组(如在SilentGhost的原始答案中)。

这对我来说似乎更可读。 (如果我习惯使用枚举,也许会感觉不一样。)CAVEAT:我没有testing过这两种方法的性能。

 # Returns a new list. "lst" is not modified. def delete_by_indices(lst, indices): indices_as_set = set(indices) return [ lst[i] for i in xrange(len(lst)) if i not in indices_as_set ] 

注意:Python 2.7语法。 对于Python 3, xrange => range

用法:

 lst = [ 11*x for x in xrange(10) ] somelist = delete_by_indices( lst, [0, 4, 5]) 

somelist:

 [11, 22, 33, 66, 77, 88, 99] 

—奖金—

从列表中删除多个值。 也就是说,我们有我们想要删除的值:

 # Returns a new list. "lst" is not modified. def delete__by_values(lst, values): values_as_set = set(values) return [ x for x in lst if x not in values_as_set ] 

用法:

 somelist = delete__by_values( lst, [0, 44, 55] ) 

somelist:

 [11, 22, 33, 66, 77, 88, 99] 

这与之前的答案相同,但是这次我们提供了要删除的VALUES [0, 44, 55]

这里是另一种方法去除元素。 如果你的名单真的很长,那就更快了。

 >>> a = range(10) >>> remove = [0,4,5] >>> from collections import deque >>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0) >>> timeit.timeit('[i for j, i in enumerate(a) if j not in remove]', setup='import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1) 0.1704120635986328 >>> timeit.timeit('deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)', setup='from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1) 0.004853963851928711 

这已被提及,但不知何故没有人设法实际做到正确。

O(n)解决scheme将是:

 indices = {0, 2} somelist = [i for j, i in enumerate(somelist) if j not in indices] 

这是非常接近SilentGhost的版本 ,但增加了两个大括号。

删除方法会导致列表元素的大量移位。 我觉得更好的做一个副本:

 ... new_list = [] for el in obj.my_list: if condition_is_true(el): new_list.append(el) del obj.my_list obj.my_list = new_list ... 

从技术上讲,答案是否定的,不可能在同一时间删除两个对象。 但是,可以删除一行美丽的Python中的两个对象。

 del (foo['bar'],foo['baz']) 

将recusrively删除foo['bar'] ,然后foo['baz']

我们可以通过使用for循环对索引进行迭代,然后按降序对索引列表进行sorting

 mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65] indexes = 4,6 indexes = sorted(indexes, reverse=True) for i in index: mylist.pop(i) print mylist 

对于listA的索引0和2:

 for x in (2,0): listA.pop(x) 

对于一些从listA中删除的随机索引:

 indices=(5,3,2,7,0) for x in sorted(indices)[::-1]: listA.pop(x) 

另一种使用列表索引值的列表理解方法:

 stuff = ['a', 'b', 'c', 'd', 'e', 'f', 'woof'] index = [0, 3, 6] new = [i for i in stuff if stuff.index(i) not in index] 

这返回:

 ['b', 'c', 'e', 'f'] 

我想要一个方法来比较不同的解决scheme,这使得它很容易转动旋钮。

首先我产生了我的数据:

 import random N = 16 * 1024 x = range(N) random.shuffle(x) y = random.sample(range(N), N / 10) 

然后我定义了我的function:

 def list_set(value_list, index_list): index_list = set(index_list) result = [value for index, value in enumerate(value_list) if index not in index_list] return result def list_del(value_list, index_list): for index in sorted(index_list, reverse=True): del(value_list[index]) def list_pop(value_list, index_list): for index in sorted(index_list, reverse=True): value_list.pop(index) 

然后我用timeit来比较解决scheme:

 import timeit from collections import OrderedDict M = 1000 setup = 'from __main__ import x, y, list_set, list_del, list_pop' statement_dict = OrderedDict([ ('overhead', 'a = x[:]'), ('set', 'a = x[:]; list_set(a, y)'), ('del', 'a = x[:]; list_del(a, y)'), ('pop', 'a = x[:]; list_pop(a, y)'), ]) overhead = None result_dict = OrderedDict() for name, statement in statement_dict.iteritems(): result = timeit.timeit(statement, number=M, setup=setup) if overhead is None: overhead = result else: result = result - overhead result_dict[name] = result for name, result in result_dict.iteritems(): print "%s = %7.3f" % (name, result) 

产量

 set = 1.711 del = 3.450 pop = 3.618 

因此, set指数发生器是赢家。 而del稍快,然后pop

我其实可以想到两种方法来做到这一点:

  1. 切片清单像(这删除了第一,第三和第八个元素)

    somelist = somelist [1:2] + somelist [3:7] + somelist [8:]

  2. 做到这一点,但一次一个:

    somelist.pop(2)somelist.pop(0)

你可以在字典上这样做,而不是在列表上。 在列表中元素是按顺序排列的。 在字典中,他们只依赖于索引。

简单的代码只是为了解释它做的事情

 >>> lst = ['a','b','c'] >>> dct = {0: 'a', 1: 'b', 2:'c'} >>> lst[0] 'a' >>> dct[0] 'a' >>> del lst[0] >>> del dct[0] >>> lst[0] 'b' >>> dct[0] Traceback (most recent call last): File "<pyshell#19>", line 1, in <module> dct[0] KeyError: 0 >>> dct[1] 'b' >>> lst[1] 'c' 

在字典中“转换”列表的方法是:

 >>> dct = {} >>> for i in xrange(0,len(lst)): dct[i] = lst[i] 

反过来是:

 lst = [dct[i] for i in sorted(dct.keys())] 

无论如何,我认为如你所说,从较高的指数开始删除会更好。

概括来自@sth的评论。 删除任何类中的项目,实现abc.MutableSequence ,特别是在list中,通过__delitem__ magic方法完成。 这个方法的作用类似于__getitem__ ,这意味着它可以接受一个整数或一个切片。 这里是一个例子:

 class MyList(list): def __delitem__(self, item): if isinstance(item, slice): for i in range(*item.indices(len(self))): self[i] = 'null' else: self[item] = 'null' l = MyList(range(10)) print(l) del l[5:8] print(l) 

这将输出

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 'null', 'null', 'null', 8, 9] 

仅仅因为这个原因才导入它可能是过度的,但是如果你碰巧使用了pandas ,那么解决scheme就简单明了:

 import pandas as pd stuff = pd.Series(['a','b','a','c','a','d']) less_stuff = stuff[stuff != 'a'] # define any condition here # results ['b','c','d'] 
 l = ['a','b','a','c','a','d'] to_remove = [1, 3] [l[i] for i in range(0, len(l)) if i not in to_remove]) 

这和顶尖的投票答案基本相同,只是写作方式不同而已。 请注意,使用l.index()不是一个好主意,因为它不能处理列表中重复的元素。