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