【问题标题】:Python removing overlap of listsPython删除列表的重叠
【发布时间】:2018-08-07 02:30:08
【问题描述】:

我知道已经有人问过这个问题的变体,但我能找到的所有问题都没有解决我的具体目标。

我试图在 Python 中使用字符串元素获取两个列表,并删除两者的重叠部分。例如:

list1 = ["25","+","7","*","6","/","7"]
list2 = ["7","*","6"]

应该去

["25","+","/","7"]

我已经考虑过类似

的列表理解
[i for i in list1 if not in list2]

但这会产生

["25","+","/"]

因为“7”的两个实例都将被删除。

我怎样才能在这里实现我想要做的事情?谢谢。

编辑 - 这被标记为可能重复。在我的列表理解示例中,我已经解释了它与链接的问题有何不同。

【问题讨论】:

  • 你可以尝试使用计数器
  • 顺序重要吗?
  • @blhsing 这不是 - 你链接的问题涉及每一个事件,而我用我的示例展示了列表理解,这不是我想要的。
  • 这类似于在较大的字符串中查找子字符串。我建议您阅读有关 KMP (Knuth-Morris-Pratt) 算法的信息,它可以直接应用于您的场景。

标签: python list


【解决方案1】:

本质上,您希望对多集(即袋子)进行差异操作。 Python implements this for the collections.Counter object:

提供了几种数学运算来组合计数器 产生多重集的对象(计数大于 零)。加法和减法通过添加或组合计数器 减去相应元素的计数。交叉口和 union 返回相应计数的最小值和最大值。每个 操作可以接受带符号计数的输入,但输出将 排除计数为零或更少的结果。

所以,例如:

>>> list1 = ["25","+","7","*","6","/","7"]
>>> list2 = ["7","*","6"]
>>> list((Counter(list1) - Counter(list2)).elements())
['25', '+', '7', '/']

在 Python 3.6+ 中,这将被订购(尽管目前不能保证,并且可能应该将其视为实现细节)。如果顺序很重要,而您没有使用此版本,则可能必须实现有序计数器。

确实,the docs themselves provide just such a recipe:

>>> from collections import Counter, OrderedDict
>>> class OrderedCounter(Counter, OrderedDict):
...     'Counter that remembers the order elements are first encountered'
...     def __repr__(self):
...         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
...     def __reduce__(self):
...         return self.__class__, (OrderedDict(self),)
...
>>> list((OrderedCounter(list1) - OrderedCounter(list2)).elements())
['25', '+', '/', '7']

【讨论】:

  • 这个解决方案实际上并不能维持秩序(即使是OrderedCounter)。试试list1 = ["6","/","7","6","7","6"]list2 = ["7","6","7"]。输出是['6', '6', '/'],而应该是['6', '/', '6']
  • @blhsing 我得到['/','6','6'],即维护list1 的秩序,但是,您是对的,这里的“维护秩序”是模棱两可的。不确定 OP 到底想要什么,他们也没有对此发表评论,但我知道“重叠”是如何暗示的。
  • 我的理解是OP想用列表来模拟字符串替换,所以就像'6/7676'.replace('767', ''),结果是'6/6',可以这么说,这就是为什么我说预期的输出这个case真的应该是['6', '/', '6']
  • @blhsing 对,我明白你在说什么,但我认为在这方面它是模棱两可的。无论如何,如果元素总是字符串,那么你可能很难击败list(''.join(list1).replace(''.join(list2), ''))
  • 是的,它有点模棱两可。但是在这种情况下,一个简单的字符串替换是行不通的,因为在 OP 的示例中,列表中有一个长度超过一个字符的字符串。
【解决方案2】:

使用remove 方法。应该很慢吧。更糟糕的情况是 O(n^2)。

list.remove(x)

Remove the first item from the list whose value is x. 
It is an error if there is no such item.
for i in list2:
    list1.remove(i)

# list1 becomes
['25', '+', '/', '7']

【讨论】:

  • 我相信这会很好,尽管根据列表的不同,它可能表现得相当糟糕。
  • @juanpa.arrivillaga 同意。添加了评论。
  • 如果配对很小(比我打赌的 dict 方法更好),我认为这表现良好。如果您正在处理两个大型列表,那么最坏情况的二次时间会影响您。
  • @juanpa.arrivillaga 感谢您让我们知道您的实验结果。
  • 这个方案其实是不维护秩序的。试试list1 = ["6","/","7","6","7","6"]list2 = ["7","6","7"]。输出应该是['/', '6', '6'],而应该是['6', '/', '6']
猜你喜欢
  • 2013-04-25
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 2014-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多