从列表中删除多个元素

2025-02-27 09:05:00
admin
原创
74
摘要:问题描述:是否可以同时从列表中删除多个元素?如果我想删除索引 0 和 2 处的元素,并尝试类似 的操作del somelist[0],然后是del somelist[2],第二条语句实际上会删除somelist[3]。我想我总是可以先删除编号较高的元素,但我希望有更好的方法。解决方案 1:出于某种原因,我不喜...

问题描述:

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

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


解决方案 1:

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

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

这有什么原因吗?我只会这样做:

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

如果您真的不想向后删除项目,那么我想您应该只减少大于最后删除的索引的索引值(由于您有不同的列表,因此不能真正使用相同的索引)或使用列表的副本(这不是“删除”,而是用编辑后的副本替换原始副本)。

我在这里是否遗漏了什么?有什么理由不按相反的顺序删除?

解决方案 2:

您可以使用enumerate和删除索引与要删除的索引匹配的值:

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

解决方案 3:

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

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

a[2:10] = []

解决方案 4:

您可以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:

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

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

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

解决方案 6:

作为函数:

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

运行时间为n log(n),这应该是迄今为止最快的正确解决方案。

解决方案 7:

那么,您本质上是想一次性删除多个元素?在这种情况下,下一个要删除的元素的位置将偏移先前删除的元素数量。

我们的目标是删除所有元音,它们被预先计算为索引 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]

如果您想按任意顺序删除元素,那么情况会更复杂。在我看来,排序to_delete可能比弄清楚何时应该或不应该从中减去更容易index

解决方案 8:

我是 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采用众所周知的格式,例如,始终为数字...

解决方案 9:

这是一种替代方法,它不使用 enumerate() 来创建元组(如 SilentGhost 的原始答案中所述)。

对我来说,这似乎更具可读性。(如果我习惯使用枚举,我可能会有不同的感觉。)警告:我还没有测试这两种方法的性能。

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

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

解决方案 10:

使用列表索引值的替代列表理解方法:

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

解决方案 11:

这是另一种删除元素的方法。如果您的列表很长,那么它会更快。

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

解决方案 12:

这一点已经有人提到过,但不知何故没人能够真正解决它。

解决O(n)方案是:

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

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

解决方案 13:

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

解决方案 14:

Remove 方法会导致列表元素大量移动。我认为最好复制一份:

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

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

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

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

解决方案 16:

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

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

解决方案 18:

概括@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]

解决方案 19:

我想要找到一种方法来比较不同的解决方案,使得转动旋钮变得容易。

首先我生成了我的数据:

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

解决方案 20:

您可以使用以下逻辑:

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

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

print c

解决方案 21:

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

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

解决方案 22:

你可能只想使用 np.delete:

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

输出

array([1, 3])

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

如果有 ndarray,则可以使用第三个参数:axis(如果是 ndarray,则 0 表示行,1 表示列)。

解决方案 23:

我使用perfplot测试了建议的解决方案,发现 NumPy 的

np.delete(lst, remove_ids)

如果列表长度超过 100 个条目,则是最快的解决方案。在此之前,所有解决方案都在 10^-5 秒左右。列表理解似乎很简单:

out = [item for i, item in enumerate(lst) if i not in remove_ids]

在此处输入图片描述


重现情节的代码:

import perfplot
import random
import numpy as np
import copy


def setup(n):
    lst = list(range(n))
    random.shuffle(lst)
    # //10 = 10%
    remove_ids = random.sample(range(n), n // 10)
    return lst, remove_ids


def if_comprehension(lst, remove_ids):
    return [item for i, item in enumerate(lst) if i not in remove_ids]


def del_list_inplace(lst, remove_ids):
    out = copy.deepcopy(lst)
    for i in sorted(remove_ids, reverse=True):
        del out[i]
    return out


def del_list_numpy(lst, remove_ids):
    return np.delete(lst, remove_ids)


b = perfplot.bench(
    setup=setup,
    kernels=[if_comprehension, del_list_numpy, del_list_inplace],
    n_range=[2**k for k in range(20)],
)
b.save("out.png")
b.show()

解决方案 24:

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

  1. 对列表进行切片(删除第 1、第 3 和第 8 个元素)

某些列表 = 某些列表[1:2]+某些列表[3:7]+某些列表[8:]

  1. 到位执行此操作,但一次只能执行一次:

一些列表.pop(2) 一些列表.pop(0)

解决方案 25:

您可以在字典上这样做,但不能在列表上这样做。列表中的元素是按顺序排列的。在字典中,它们仅取决于索引。

简单的代码只是为了解释一下

>>> 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())] 

无论如何,我认为最好按照您说的从较高的索引开始删除。

解决方案 26:

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

解决方案 27:

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

避免排序成本和必须明确复制列表。

解决方案 28:

到目前为止提供的所有答案都没有在 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]

解决方案 29:

这些怎么样(我对 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)

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

解决方案 30:

我把它们放在一起放入一个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']
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3868  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2711  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   44  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   42  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   44  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用