Answers:
可能不是此问题的最佳解决方案:
indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]
somelist = [ lst[i] for i in xrange(len(lst)) if i not in set(indices) ]
?
由于某种原因,我不喜欢这里的任何答案。是的,它们可以工作,但是严格来说,大多数不是删除列表中的元素,对吗?(但是要进行复制,然后用编辑后的副本替换原始副本)。
为什么不先删除较高的索引呢?
是否有一个原因?我会做:
for i in sorted(indices, reverse=True):
del somelist[i]
如果您真的不想向后删除项目,那么我想您应该减少大于上一个删除索引的索引值(因为您使用的是不同的列表,所以不能真正使用相同的索引)或使用列表的副本(不会被“删除”,而是将原件替换为已编辑的副本)。
我是否在这里缺少任何东西,有什么理由不以相反的顺序删除?
如果要删除多个不相邻的项目,那么您描述的是最好的方法(是的,请确保从最高索引开始)。
如果您的项目相邻,则可以使用切片分配语法:
a[2:10] = []
del a[2:10]
具有相同的效果。
您可以使用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()
。您还将看到一些相当大的速度改进,从而使它成为更具可扩展性的解决方案。我尚未对其进行基准测试,但是numpy
操作是用C或Fortran编写的已编译代码。
作为功能:
def multi_delete(list_, *args):
indexes = sorted(list(args), reverse=True)
for index in indexes:
del list_[index]
return list_
以n log(n)时间运行,这应该使其成为最快的正确解决方案。
n log n
?真?我认为del list[index]
不是O(1)。
因此,您本质上想一次删除多个元素吗?在这种情况下,下一个要删除的元素的位置将被偏移,但是之前删除了许多元素。
我们的目标是删除所有预计算为索引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]
如果您想以任何顺序删除元素,将更加复杂。IMO,排序to_delete
可能比弄清楚何时应该从中减去应该不容易index
。
我是Python的初学者,至少我现在的编程很粗糙,但是我的解决方案是结合使用我在早期教程中学到的基本命令:
some_list = [1,2,3,4,5,6,7,8,10]
rem = [0,5,7]
for i in rem:
some_list[i] = '!' # mark for deletion
for i in range(0, some_list.count('!')):
some_list.remove('!') # remove
print some_list
显然,由于必须选择“删除标记”字符,因此有其局限性。
至于列表大小可扩展的性能,我确定我的解决方案不是最佳的。但是,它很简单,我希望能吸引其他初学者,并且可以在some_list
格式众所周知的简单情况下使用,例如始终为数字...
这是一种替代方法,它不使用enumerate()创建元组(如SilentGhost的原始答案)。
这对我来说似乎更具可读性。(如果我习惯于使用枚举,也许会有所不同。)CAVEAT:我尚未测试两种方法的性能。
# 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])
清单:
[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] )
清单:
[11, 22, 33, 66, 77, 88, 99]
这是与以前相同的答案,但是这次我们提供了要删除的VALUES [0, 44, 55]
。
[ value for (i, value) in enumerate(lst) if i not in set(indices) ]
。但是,我将在这里保留我的答案,因为我还将显示如何按值删除。这是一个简单的案例,但可能会对某人有所帮助。
indices_as_set = set(indices)
,[ value for (i, value) in enumerate(lst) if i not in indices_as_set ]
以加快速度。
delete__by_values()
吗?
这是另一种删除适当元素的方法。同样,如果您的清单很长,则速度会更快。
>>> 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)
解决办法是:
indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]
这确实接近SilentGhost的版本,但增加了两个花括号。
O(n)
如果您要计算log(len(indices))
每次迭代的查找次数,则不是这样。
j not in indices
是O(1)
。
j not in indices
仍需要查找,即O(log(len(indices)))
。虽然我同意2元素集中的查找符合条件O(1)
,但一般情况下是O(log(N))
。任一种方法O(N log(N))
仍然有效O(N^2)
。
j not in indices
是O(1)
认真的。
从技术上讲,答案是否定的,不可能在同一时间删除两个对象。但是,可以在一行漂亮的python中删除两个对象。
del (foo['bar'],foo['baz'])
将删除后foo['bar']
,foo['baz']
我们可以通过在索引列表降序排序后使用for循环遍历索引来实现此目的
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
我想找到一种比较不同解决方案的方法,这些解决方案可以轻松旋转旋钮。
首先,我生成了数据:
import random
N = 16 * 1024
x = range(N)
random.shuffle(x)
y = random.sample(range(N), N / 10)
然后我定义了我的功能:
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
比较解决方案:
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
因此,索引为a的生成器set
就是赢家。然后del
快一点pop
。
从最高索引中删除的想法的另一种实现。
for i in range(len(yourlist)-1, -1, -1):
del yourlist(i)
您可以对字典而不是列表进行这种操作。在列表中,元素是按顺序排列的。在字典中,它们仅取决于索引。
简单的代码只是为了解释这样做:
>>> 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
,则解决方案非常简单明了:
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']
其中之一怎么样(我是Python的新手,但看起来还不错):
ocean_basin = ['a', 'Atlantic', 'Pacific', 'Indian', 'a', 'a', 'a']
for i in range(1, (ocean_basin.count('a') + 1)):
ocean_basin.remove('a')
print(ocean_basin)
[“大西洋”,“太平洋”,“印度”]
ob = ['a', 'b', 4, 5,'Atlantic', 'Pacific', 'Indian', 'a', 'a', 4, 'a']
remove = ('a', 'b', 4, 5)
ob = [i for i in ob if i not in (remove)]
print(ob)
[“大西洋”,“太平洋”,“印度”]
到目前为止提供的答案都不进行删除到位的O(N)在列表的长度为指标,删除任意数量的,所以这里是我的版本:
def multi_delete(the_list, indices):
assert type(indices) in {set, frozenset}, "indices must be a set or frozenset"
offset = 0
for i in range(len(the_list)):
if i in indices:
offset += 1
elif offset:
the_list[i - offset] = the_list[i]
if offset:
del the_list[-offset:]
# Example:
a = [0, 1, 2, 3, 4, 5, 6, 7]
multi_delete(a, {1, 2, 4, 6, 7})
print(a) # prints [0, 3, 5]
我将所有内容放到一个list_diff
函数中,该函数仅将两个列表作为输入并返回它们的差,同时保留第一个列表的原始顺序。
def list_diff(list_a, list_b, verbose=False):
# returns a difference of list_a and list_b,
# preserving the original order, unlike set-based solutions
# get indices of elements to be excluded from list_a
excl_ind = [i for i, x in enumerate(list_a) if x in list_b]
if verbose:
print(excl_ind)
# filter out the excluded indices, producing a new list
new_list = [i for i in list_a if list_a.index(i) not in excl_ind]
if verbose:
print(new_list)
return(new_list)
用法示例:
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'woof']
# index = [0, 3, 6]
# define excluded names list
excl_names_list = ['woof', 'c']
list_diff(my_list, excl_names_list)
>> ['a', 'b', 'd', 'e', 'f']