从列表中删除第一个遇到的元素

bon*_*hev 11 python list

我有两个具有相同数量元素的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)


Ev.*_*nis 8

我可能会在这里打码,但我觉得这很有趣:

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)

如果您不熟悉列表推导,此处发生的事情如下(从最后读取):

  • 我检查元素是否ilist2存在的一个切片list2,其中包括以前所有的元素list2[:i].
  • 如果它然后我从list1(x)捕获相应的元素,我将其存储在我正在创建的新列表中list1_new

  • 这具有二次运行时间.不完全是我所理解的"有效". (3认同)
  • 我不认为这对任务来说非常重要.即使原始列表有数千个条目,运行时间的差异也应该是毫秒,但正如我所说的那样,我把它看成是一个有趣的,而不是最有效的. (2认同)

Jak*_*ube 7

一种有效的方法是使用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实际上并没有复制字符串,只是创建了一个指向原始字符串的指针.