从列表中删除多个元素

时间:2009-01-30 21:59:39

标签: python list

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

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

30 个答案:

答案 0 :(得分:132)

出于某种原因,我不喜欢这里的任何答案。 是的,它们可以工作,但严格来说,大多数都没有删除列表中的元素,是吗? (但制作副本,然后用编辑后的副本替换原来的副本)。

为什么不先删除较高的索引?

这有什么理由吗? 我会这样做:

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

如果你真的不想向后删除项目,那么我猜你应该只是减去索引值,这些值大于上次删除的索引(由于你有不同的列表,所以不能真正使用相同的索引)或使用列表的副本(不是'删除',而是用编辑后的副本替换原件)。

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

答案 1 :(得分:101)

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

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

a[2:10] = []

答案 2 :(得分:90)

可能不是此问题的最佳解决方案:

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

答案 3 :(得分:18)

作为一项功能:

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

n log(n)时间运行,这应该是目前最快的正确解决方案。

答案 4 :(得分:17)

您可以按如下方式使用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编写的编译代码。

答案 5 :(得分:17)

作为Greg答案的专长,您甚至可以使用扩展切片语法。例如。如果要删除项目0和2:

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

当然,这并不涵盖任何选择,但它肯定可以用于删除任何两个项目。

答案 6 :(得分:11)

那么,你基本上想要一次删除多个元素?在这种情况下,要删除的下一个元素的位置将被偏移,但之前删除了许多元素。

我们的目标是删除预先计算为索引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减去更容易。

答案 7 :(得分:6)

我是Python的初学者,目前我的编程简直粗糙,但我的解决方案是使用我在早期教程中学到的基本命令的组合:

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

显然,由于必须选择“删除标记”字符,这有其局限性。

至于表格大小的表现,我确信我的解决方案不是最优的。然而,它很简单,我希望吸引其他初学者,并且可以在SomeList具有众所周知格式的简单情况下工作,例如,总是数字......

答案 8 :(得分:5)

这是另一种选择,它不使用enumerate()来创建元组(如在SilentGhost' s原始答案中)。

这对我来说似乎更具可读性。 (如果我习惯使用枚举,也许我会有不同的感受。)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])

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]

答案 9 :(得分:4)

使用列表索引值的替代列表推导方法:

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

答案 10 :(得分:4)

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

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

答案 11 :(得分:3)

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

O(n)解决方案将是:

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

这非常接近SilentGhost's version,但增加了两个括号。

答案 12 :(得分:3)

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()不是一个好主意,因为它无法处理列表中的重复元素。

答案 13 :(得分:2)

我想要一种比较不同解决方案的方法,这些解决方案可以轻松转动旋钮。

首先我生成了我的数据:

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

因此,set指数的发电机是赢家。而delpop略快一些。

答案 14 :(得分:2)

删除方法会导致列表元素的大量移位。我认为最好复制一份:

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

答案 15 :(得分:2)

对于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)

答案 16 :(得分:2)

我们可以通过在按降序对索引列表进行排序后使用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

答案 17 :(得分:2)

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

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

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

答案 18 :(得分:1)

你可以在dict上这样做,而不是在列表上。列表元素按顺序排列。在一个词典中,他们只依赖于指数。

简单的代码只是通过来解释

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

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

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

反过来是:

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

无论如何,我认为如你所说,最好从更高的索引开始删除。

答案 19 :(得分:1)

概括来自@sth的评论。任何类中的项目删除,实现abc.MutableSequence,特别是list,都是通过__delitem__魔术方法完成的。此方法与__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]

答案 20 :(得分:1)

仅因为这个原因导入它可能有点过分,但如果你碰巧正在使用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']

答案 21 :(得分:1)

我实际上可以想到两种方法:

  1. 将列表切片为(这将删除第1个,第3个和第8个元素)

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

  2. 这样做,但一次一个:

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

答案 22 :(得分:1)

您可以使用此逻辑:

my_list = ['word','yes','no','nice']

c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]

print c

答案 23 :(得分:1)

some_list.remove(some_list[max(i, j)])

避免分拣成本并且必须明确复制列表。

答案 24 :(得分:1)

从最高索引中删除的想法的另一种实现方式。

for i in range(len(yourlist)-1, -1, -1):
    del yourlist(i)

答案 25 :(得分:1)

您可能只想使用np.delete:

list_indices = [0, 2]
original_list = [0, 1, 2, 3]
new_list = np.delete(original_list, list_indices)

输出

array([1, 3])

在这里,第一个参数是原始列表,第二个参数是您要删除的索引或索引列表。

在具有ndarray的情况下,可以使用第三个参数:(对于ndarray,行为0,列为1)。

答案 26 :(得分:0)

其中之一怎么样(我是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)

['大西洋','太平洋','印度']

答案 27 :(得分:0)

到目前为止,没有提供的答案在列表长度的O(n)中执行删除(em)到位(em),可以删除任意数量的索引,所以这是我的版本:

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]

答案 28 :(得分:0)

您也可以使用remove。

delete_from_somelist = []
for i in [int(0), int(2)]:
     delete_from_somelist.append(somelist[i])
for j in delete_from_somelist:
     newlist = somelist.remove(j)

答案 29 :(得分:0)

我将所有内容整合到一个function defaultConfiguration() { $default_config = \Drupal::config('burnblock_hooks.settings'); return [ 'hello_block_name' => $default_config->get('hello.name'), ]; } 函数中,该函数仅将两个列表作为输入并返回它们的差,同时保留第一个列表的原始顺序。

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)