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

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

解决方案:使用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时。
>>>

猜你喜欢

转载自www.cnblogs.com/jeffrey-yang/p/11290841.html