1. 程式人生 > 其它 >1.10 刪除序列中的重複元素並保持順序

1.10 刪除序列中的重複元素並保持順序

怎樣在一個序列上面保持元素順序的同時消除重複的值?

問題描述

怎樣在一個序列上面保持元素順序的同時消除重複的值?

解決方案

如果序列上的值都是hashable型別(簡言之,python中不可變物件就是hashable型別的,具體介紹參考官方文件),那麼可以很簡單的利用集合或者生成器解決這個問題:

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]
res = list(dedupe(a))
# res = [1, 5, 2, 9, 10]

這個方法僅在序列元素為hashable時可用。如果你想消除元素不可雜湊的序列(比如dict)中重複元素的話,需要將上述程式碼稍作修改:


def dedupe(items, key=None):
	"""
	這裡的key引數指定了一個函式,將items中元素轉化成了hashable型別。
	"""
    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)
    return seen


a = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
res = list(dedupe(a, key=lambda d: (d['x'], d['y'])))
# res = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
re = list(dedupe(a, key=lambda d: (d['x'])))
# re = [{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]

討論

如果你只想消除重複元素,通常可以簡單的構造一個集合。比如:

a = [1, 5, 2, 1, 9, 1, 5, 10]
res = set(a)
# res = {1, 2, 5, 9, 10}

然而這種方法不能維護元素的順序。

在本節中,我們使用了生成器函式讓我們的函式更加通用,不僅僅是侷限於列表處理。比如,如果你想讀取一個檔案,消除重複行,你可以這樣做:

with open(file, 'r') as f:
	for line in dedupe(f):
		...

上述key函式引數模仿了sorted(),min()max()等內建函式的相似功能。可以參考1.8和1.13小節瞭解更多。