我有两个具有相同数量元素的Python列表.第一个列表的元素是唯一的,第二个列表中的元素 - 不一定如此.例如
list1 = ['e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7']
list2 = ['h1', 'h2', 'h1', 'h3', 'h1', 'h2', 'h4']
Run Code Online (Sandbox Code Playgroud)
我想删除第二个列表中的所有"第一次遇到"元素及其第一个列表中的相应元素.基本上,这意味着删除所有唯一元素和重复项的第一个元素.通过上面的例子,应该是正确的结果
>>>list1
['e3', 'e5', 'e6']
>>>list2
['h1', 'h1', 'h2']
Run Code Online (Sandbox Code Playgroud)
也就是说,元素'e1'被删除了,因为第一次遇到了相应的'h1','e2'被删除了,因为第一次看到'h2',因为'h1'已经'e3'了看到'e4'被删除了,因为第一次看到'h3','e5'被留下了因为'h1'已经被看到了,'e6'被留下了因为'h2'已经被看到了,'e7'被删除了因为'h4'是第一次出现.
什么是解决这个问题的有效方法?列表可能包含数千个元素,因此如果可能的话,我宁愿不复制它们或运行多个循环.
the*_*eye 10
只需使用一个set对象来查找是否已经看到当前值,就像这样
>>> list1 = ['e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7']
>>> list2 = ['h1', 'h2', 'h1', 'h3', 'h1', 'h2', 'h4']
>>>
>>> def filterer(l1, l2):
... r1 = []
... r2 = []
... seen = set()
... for e1, e2 in zip(l1, l2):
... if e2 not in seen:
... seen.add(e2)
... else:
... r1.append(e1)
... r2.append(e2)
... return r1, r2
...
>>> list1, list2 = filterer(list1, list2)
>>> list1
['e3', 'e5', 'e6']
>>> list2
['h1', 'h1', 'h2']
Run Code Online (Sandbox Code Playgroud)
如果您要逐个使用元素,如果输入列表非常大,那么我建议制作一个生成器,就像这样
>>> def filterer(l1, l2):
... seen = set()
... for e1, e2 in zip(l1, l2):
... if e2 not in seen:
... seen.add(e2)
... else:
... yield e1, e2
...
>>> list(filterer(list1, list2))
[('e3', 'h1'), ('e5', 'h1'), ('e6', 'h2')]
>>>
>>> zip(*filterer(list1, list2))
[('e3', 'e5', 'e6'), ('h1', 'h1', 'h2')]
Run Code Online (Sandbox Code Playgroud)
我可能会在这里打码,但我觉得这很有趣:
list1_new = [x for i, x in enumerate(list1) if list2[i] in list2[:i]]
print(list1_new)
# prints ['e3', 'e5', 'e6']
Run Code Online (Sandbox Code Playgroud)
如果您不熟悉列表推导,此处发生的事情如下(从最后读取):
i中list2存在的一个切片list2,其中包括以前所有的元素list2[:i].list1(x)捕获相应的元素,我将其存储在我正在创建的新列表中list1_new一种有效的方法是使用set包含所有已经看到的键的a.A set将保证您的平均查找O(1).
所以像这样的东西应该工作:
s = set()
result1 = []
result2 = []
for x, y in zip(list1, list2):
if y in s:
result1.append(x)
result2.append(y)
else:
s.add(y)
Run Code Online (Sandbox Code Playgroud)
请注意,这将创建一个新列表.不过应该不是一个大问题,因为Python实际上并没有复制字符串,只是创建了一个指向原始字符串的指针.