如何删除 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)
基本上现在 li1
和 ret
都包含相同的内部列表。因此,当您执行 ret[i].remove(el2)
时,它会从 li1
和 ret
中删除它。
您可以通过将 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]);
环境: 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)
基本上现在 li1
和 ret
都包含相同的内部列表。因此,当您执行 ret[i].remove(el2)
时,它会从 li1
和 ret
中删除它。
您可以通过将 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]);