Python實用技法第9篇:從序列中移除重複項且保持元素間順序不變

Mark發表於2019-02-16

上一篇文章:Python實用技法第8篇:在兩個字典中尋找相同點
下一篇文章:Python實用技法第10篇:對切片命名

1、需求?

我們想去除序列出現的重複元素,但仍然保持剩下的元素的順序不變。

如果只是想要去重,那麼通常足夠簡單的方法就是構建一個集合:

a=[1,5,4,36,7,8,2,3,5,7]
#結果為:{1, 2, 3, 4, 5, 36, 7, 8}
print(set(a))

2、解決方案?

如果序列中的值是可雜湊的(hashable),那麼這個問題可以通過使用集合和生成器輕鬆解決。

如果一個物件是可雜湊的,那麼它的生存期內必須是不可變的,它需要有一個__hash__()方法。整數、浮點數、字串、元素都是不可變的。

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

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

執行結果:

[1, 2, 3, 9, 5, 10]

只有當序列中的元素是可雜湊的時候才能這麼做。如果想在不可雜湊的物件序列中去除重複項,需要上述程式碼稍作修改:

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

a=[
    {`x`:1,`y`:2},
    {`x`:1,`y`:3},
    {`x`:1,`y`:4},
    {`x`:1,`y`:2},
    {`x`:1,`y`:3},
    {`x`:1,`y`:1},

]
print(list(dedupe(a,key=lambda d:(d[`x`],d[`y`]))))

print(list(dedupe(a,key=lambda d:d[`y`])))

執行結果:

[{`x`: 1, `y`: 2}, {`x`: 1, `y`: 3}, {`x`: 1, `y`: 4}, {`x`: 1, `y`: 1}]
[{`x`: 1, `y`: 2}, {`x`: 1, `y`: 3}, {`x`: 1, `y`: 4}, {`x`: 1, `y`: 1}]

這裡的引數key的作用是指定一個函式用來將序列中的元素轉換為可雜湊的型別,那麼做的目的是為了檢測重複項。

上一篇文章:Python實用技法第8篇:在兩個字典中尋找相同點
下一篇文章:Python實用技法第10篇:對切片命名

相關文章