【问题标题】:Remove elements from a list that occur in another list and return their indices从列表中删除出现在另一个列表中的元素并返回它们的索引
【发布时间】:2018-10-05 09:12:57
【问题描述】:

这个list,例如:

my_list = ['a', 'd', 'a', 'd', 'c','e']
words_2_remove = ['a', 'c']

输出应该是:

my_list = ['d', 'd', 'e']
loc = [0, 2, 4]

我目前正在使用这个:

loc = []    
for word in my_list:  
    if word in words_2_remove:
         loc.append( my_list.index(word) )
         my_list.remove(word)

有更好的选择吗?

【问题讨论】:

  • 在哪种意义上更好?
  • @Georgy Better 可能更高效或更灵活。例如,可能需要找到索引loc 的补码;然后,他可以将not 添加到下面提供的代码中,例如:loc = [i for i, x in enumerate(my_list) if x not in words_2_remove]

标签: python algorithm list


【解决方案1】:

做两个列表理解:

my_list =['a', 'd', 'a', 'd', 'c','e']
words_2_remove = ['a', 'c']

loc = [i for i, x in enumerate(my_list) if x in words_2_remove]

my_list = [x for x in my_list if x not in words_2_remove]

print(my_list) # ['d', 'd', 'e']
print(loc)     # [0, 2, 4]

【讨论】:

  • 第四行可以换成my_list = [my_list[i] for i in loc]
  • @innuendo 不,这给了你相反的结果 - my_list 中的所有项目也在 words_2_remove 中。
【解决方案2】:

对于更大的数组,使用 NumPy 会更高效:

import numpy as np


my_list = np.array(['a', 'd', 'a', 'd', 'c','e'])
words_2_remove = np.array(['a', 'c'])

mask = np.isin(my_list, words_2_remove, invert=True)
# mask will be [False  True False  True False  True]
loc = np.where(~mask)[0]

print(loc)
>>> [0 2 4]

print(my_list[mask])
>>> ['d' 'd' 'e']

而且得到loc 索引的补码也很容易:

print(np.where(mask)[0])
>>> [1 3 5]

时间安排:
与@Austin 的列表推导版本比较。
对于原始数组:

my_list = np.array(['a', 'd', 'a', 'd', 'c','e'])
words_2_remove = np.array(['a', 'c'])

%%timeit
mask = np.isin(my_list, words_2_remove, invert=True)
loc = np.where(~mask)[0]
>>> 11 µs ± 53.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

my_list =['a', 'd', 'a', 'd', 'c','e']
words_2_remove = ['a', 'c']

%%timeit
loc = [i for i, x in enumerate(my_list) if x in words_2_remove]
res = [x for x in my_list if x not in words_2_remove]
>>> 1.31 µs ± 7.17 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

对于大数组:

n = 10 ** 3
my_list = np.array(['a', 'd', 'a', 'd', 'c','e'] * n)
words_2_remove = np.array(['a', 'c'])

%%timeit
mask = np.isin(my_list, words_2_remove, invert=True)
loc = np.where(~mask)[0]
>>> 114 µs ± 906 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

my_list =['a', 'd', 'a', 'd', 'c','e'] * n
words_2_remove = ['a', 'c']

%%timeit
loc = [i for i, x in enumerate(my_list) if x in words_2_remove]
res = [x for x in my_list if x not in words_2_remove]
>>> 841 µs ± 677 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

根据用例,您可以选择更适合的。


延伸阅读:

np.isin 上的文档:https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.isin.html
将布尔掩码数组转换为索引:How to turn a boolean array into index array in numpy
np.where 上的文档:https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.where.html
有关使用 NumPy 进行索引的更多信息:https://docs.scipy.org/doc/numpy-1.15.1/reference/arrays.indexing.html

【讨论】:

    【解决方案3】:

    使用列表推导枚举

    loc = [idx for idx, item in enumerate(my_list) if item in words_2_remove]
    my_list = [i for i in my_list if i not in words_2_remove]
    

    或者使用过滤器

    my_list = list(filter(lambda x: x not in words_2_remove, my_list))
    

    扩展解释:

    loc = []
    new_my_list = []
    for idx, item in enumerate(my_list):
        if item in words_2_remove:
            loc.append(idx)
        else:
            new_my_list.append(item)
    

    【讨论】:

    • @Austin 你在说什么not 那里! :)
    • 好吧,即使是not,我也能看到!大声笑。
    猜你喜欢
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 2022-06-16
    • 1970-01-01
    • 2022-11-13
    相关资源
    最近更新 更多