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

时间:2018-01-17 07:49:58

标签: python python-3.x

环境: python 3.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']]

7 个答案:

答案 0 :(得分:2)

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

尝试使用ret.append(el1[:])使用切片运算符创建副本。其他创建列表副本的方法如下所示:How to clone or copy a list?

答案 1 :(得分:0)

一个简单的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']]

答案 2 :(得分:0)

代码中的问题是使用此行

ret.append(el1)

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

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

,从而使代码正常工作

答案 3 :(得分:0)

因为python中的所有东西都是对象,而list是可变的。 这很容易测试:

>>> 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 是一个建议

答案 4 :(得分:0)

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

# BAD:

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

这将改变传递给它的列表,并将相同的列表返回给调用者。

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

传递的列表未被修改,并且具有预期结果的单独列表将返回给调用者。

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

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

答案 5 :(得分:0)

我复制列表的方法不是复制值而是复制参考。

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

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

ret.append(el1[:])

import copy
ret = copy.deepcopy(li1)

ret.append(list(el1))

或其他。

感谢很多答案。

答案 6 :(得分:0)

试试此代码

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