如何删除 python3 列表中的重复元素?

How to remove duplicated element in list in python3?

环境: python3.6.4

我有两个列表,
list1 是嵌套的单词列表,例如

[['this', 'is', 'a', 'pen', 'that', 'is', 'a', 'desk'],
 ['this', 'is', 'an', 'apple']]

list2 是要从 list1 中删除的单词列表,例如

['a', 'an']

我想获得像

这样的新列表
[['this', 'is', 'pen', 'that', 'is', 'desk'],
 ['this', 'is', 'apple']]

并且不会更改 list1。

我写了下面的代码,但是我的代码破坏了list1,我的代码哪里错了?

def remove_duplicate_element_in_nested_list(li1, li2):
    """
    :param li1: <list> nested_sentences
    :param li2: <list> words_to_remove
    :return: <list>
    """
    ret = []
    for el1 in li1:
        ret.append(el1)

    for i in range(len(ret)):
        for el2 in li2:
            try:
                # list.remove() remove only one element. so loop this.
                for el in ret[i]:
                    ret[i].remove(el2)
            except ValueError:
                None

    return ret

words = [['this', 'is', 'a', 'pen', 'this', 'is', 'a', 'desk'], ['this', 'is', 'an', 'apple']]
stop_words = ['a', 'an']

print(words)
# shows [['this', 'is', 'a', 'pen', 'that', 'is', 'a', 'desk'], ['this', 'is', 'an', 'apple']]
new_words = remove_duplicate_element_in_nested_list(words, stop_words)
print(words)
# shows [['this', 'is', 'pen', 'that', 'is', 'desk'], ['this', 'is', 'apple']]

一个简单的for循环方法。

def remove_duplicate_element_in_nested_list(li1, li2):
    """
    :param li1: <list> nested_sentences
    :param li2: <list> words_to_remove
    :return: <list>
    """    
    ret = []
    for i in li1:
        r = []
        for k in i:
            if k not in li2:
                r.append(k)
        ret.append(r)

    return ret

A = [['this', 'is', 'a', 'pen', 'that', 'is', 'a', 'desk'], ['this', 'is', 'an', 'apple']]
B =  ['a', 'an'] 
print(remove_duplicate_element_in_nested_list(A, B))

结果:

[['this', 'is', 'pen', 'that', 'is', 'desk'], ['this', 'is', 'apple']]

您的代码中的问题出在这一行

ret.append(el1)

基本上现在 li1ret 都包含相同的内部列表。因此,当您执行 ret[i].remove(el2) 时,它会从 li1ret 中删除它。

您可以通过将 ret.append(el1) 行更改为 ret.append(list(el1))

来让您的代码正常工作

ret.append(el1) 不会复制内部列表,而是将 reference 复制到内部列表。

尝试使用 ret.append(el1[:]),它使用切片运算符创建副本。此处说明了创建列表副本的其他方法:How to clone or copy a list?

因为在 python 中一切都是对象,而且列表是可变的。 很容易测试:

>>> lst = [[1], [2]]
>>> new_lst = []
>>> for e in lst:
...     new_lst.append(e)
...
>>> new_lst[0] is lst[0]
True
>>> new_lst[0].append(10)
>>> new_lst
[[1, 10], [2]]
>>> lst
[[1, 10], [2]]

copy.deepcopy是一个建议

您必须认识到列表是可变的,当您将它们传递给函数时,它们是对同一对象的引用,如果您不知道其工作原理,可能会产生意想不到的结果。例如...

# BAD:

def filter_foo(some_list):
    while 'foo' in some_list:
        some_list.remove('foo')
    return some_list

这将改变传递给它的列表以及 return 传递给调用者的相同列表。

>>> a = ['foo', 'bar', 'baz']
>>> b = filter_foo(a)
>>> a # was modified; BAD
['bar', 'baz']
>>> b is a # they're actually the same object
True

下面通过创建一个新列表来避免这个问题

# GOOD:

def filter_foo(some_list):
    new_list = []
    for item in some_list:
        if item != 'foo':
            new_list.append(item)
    return new_list

传递的列表未被修改,一个包含预期结果的单独列表已return发送给调用者。

>>> b = filter_foo(a)
>>> a # not modified
['foo', 'bar', 'baz']
>>> b
['bar', 'baz']
>>> a is b
False

不过,这需要重构。要修复执行此操作的位置,一个简单的解决方案是复制一份。

# Drop-in fix for bad example:

def filter_foo(some_list):
    some_list = some_list[:] # make a copy
    # rest of code as it was
    return some_list

一个不同的、易于阅读的简单递归解决方案。添加了一些评论以防有任何不清楚的地方。

def filter_words(word_list, filtered_words):
    new_list = []
    for item in word_list:
        if isinstance(item, list):
            # if it's a list... filter that list then append it
            new_list.append(filter_words(item, filtered_words))
        # otherwise it must be a word...
        elif item in filtered_words:
            # if it's in our excluded words, skip it
            continue
        else:
            # it's a word, it's not excluded, so we append it.
            new_list.append(item)

测试

>>> filter_words(l, ['a', 'an'])
[['this', 'is', 'pen', 'that', 'is', 'desk'], ['this', 'is', 'apple']]    

无论列表嵌套多深(达到递归限制),这都应该有效。也可以重构为任何所需的嵌套级别。

我复制列表的方式不是复制值而是复制引用。

 ret = []
 for el1 in li1:
     ret.append(el1)

在这种情况下,我必须复制值,方法如下。

ret.append(el1[:])

import copy
ret = copy.deepcopy(li1)

ret.append(list(el1))

或其他。

非常感谢您的回答。

试试这个代码

list1=[['this', 'is', 'a', 'pen', 'that', 'is', 'a', 'desk'],['this', 'is', 'an', 'apple']]
list2=['a', 'an']
for out in range(0, len(list1)):
  for _in in range(0,len(list1[out])):
    if list1[out][_in]==list2[out]:
       list1.remove(list1[0][1]);