维护序列项顺序的同时消除重复项

Posted jeffrey-yang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了维护序列项顺序的同时消除重复项相关的知识,希望对你有一定的参考价值。

在序列中,经常会碰到有重复项的情况,有时需要消除重复的项。

解决方案:使用set来构造无重复数据项类型。如:

a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> set(a)
1, 2, 10, 5, 9

使用set构造数据后,原始的序列元素失去了当初的相对顺序。同时简单的使用set会有另一个问题:可哈希。我们知道,像list中包含list或dict等符合类型且作为set的构造函数参数进行set对象创建时,会有以下报错:

>>> c = ['x': 1, 'y': 2, 'x': 2, 'y': 3]
>>> set(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

为了解决上述问题,我们可以写一个函数先消除hash的序列的重复项消除,同时保持原有的子项的相对顺序。

def dedupe(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)

>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(dedupe(a))
[1, 5, 2, 9, 10]

通过构造一个生成器,并按原始顺序遍历items。每次遍历的时候,检查元素是否在集合容纳器中,若不在,则返回,并添加到set中。若已在set中,则跳过,继续遍历。

该函数仅对序列中所有子项全部可hash时有用。负责在进行集合add时会报错。

我们可以改进上述函数的实现,使其可以对不可hash(如dict)的对象进行特殊处理,如下:

def dedupe(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)

>>> a = [ 'x':1, 'y':2, 'x':1, 'y':3, 'x':1, 'y':2, 'x':2, 'y':4] 
>>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
['x': 1, 'y': 2, 'x': 1, 'y': 3, 'x': 2, 'y': 4]
>>> list(dedupe(a, key=lambda d: d['x']))
['x': 1, 'y': 2, 'x': 2, 'y': 4]
>>>

提供一个类似max, min中的key函数参数,然后在实际调用时使用lambda匿名函数,实际val的值由匿名函数的返回值提供,若key不为None时。
>>>

以上是关于维护序列项顺序的同时消除重复项的主要内容,如果未能解决你的问题,请参考以下文章

在保留顺序函数的同时删除向量中的重复项的逻辑错误

在 Python 中,从列表中删除重复项以使所有元素都是唯一的*同时保留顺序*的最快算法是啥? [复制]

消除列表中重复项的最佳方法,但保持先前的相对顺序 [重复]

删除左表上的重复项,同时在右表SELECT JOIN上保留重复项

如何在保留顺序的同时删除列表中的重复元素?

C++ 删除存在于另一个向量中的向量项,同时保留顺序