簡體   English   中英

從列表列表中有效地刪除重復項,與順序無關

[英]Efficiently remove duplicates, order-agnostic, from list of lists

下面的列表有一些重復的子列表,元素的順序不同:

l1 = [
    ['The', 'quick', 'brown', 'fox'],
    ['hi', 'there'],
    ['jumps', 'over', 'the', 'lazy', 'dog'],
    ['there', 'hi'],
    ['jumps', 'dog', 'over','lazy', 'the'],
]

如何刪除重復項,保留看到的第一個實例,以獲得:

l1 = [
    ['The', 'quick', 'brown', 'fox'],
    ['hi', 'there'],
    ['jumps', 'over', 'the', 'lazy', 'dog'],
]

我試過了:

[list(i) for i in set(map(tuple, l1))]

盡管如此,我不知道這是否是大型列表的最快方法,而且我的嘗試沒有按預期工作。 知道如何有效地刪除它們嗎?

這個有點棘手。 您想從凍結的計數器中鍵入一個 dict,但計數器在 Python 中不可散列。 對於漸近復雜性的小幅下降,您可以使用排序元組作為凍結計數器的替代品:

seen = set()
result = []
for x in l1:
    key = tuple(sorted(x))
    if key not in seen:
        result.append(x)
        seen.add(key)

單行中的相同想法如下所示:

[*{tuple(sorted(k)): k for k in reversed(l1)}.values()][::-1]

我做了一個快速基准測試,比較了各種答案:

l1 = [['The', 'quick', 'brown', 'fox'], ['hi', 'there'], ['jumps', 'over', 'the', 'lazy', 'dog'], ['there', 'hi'], ['jumps', 'dog', 'over','lazy', 'the']]

from collections import Counter

def method1():
    """manually construct set, keyed on sorted tuple"""
    seen = set()
    result = []
    for x in l1:
        key = tuple(sorted(x))
        if key not in seen:
            result.append(x)
            seen.add(key)
    return result

def method2():
    """frozenset-of-Counter"""
    return list({frozenset(Counter(lst).items()): lst for lst in reversed(l1)}.values())

def method3():
    """wim"""
    return [*{tuple(sorted(k)): k for k in reversed(l1)}.values()][::-1]

from timeit import timeit

print(timeit(lambda: method1(), number=1000))
print(timeit(lambda: method2(), number=1000))
print(timeit(lambda: method3(), number=1000))

印刷:

0.0025010189856402576
0.016385524009820074
0.0026451340527273715

@wim 的答案效率低下,因為它將列表項排序為唯一標識一組列表項計數的一種方式,每個子列表的時間復雜度為O(n log n)

為了以線性時間復雜度實現相同的效果,您可以使用帶有collections.Counter類的項目計數的凍結collections.Counter 由於 dict comprehension 保留了帶有重復鍵的項目的最后一個值,並且由於您希望在問題中保留帶有重復鍵的項目的第一個值,因此您必須以列表的相反順序構造 dict,然后再將其反轉已構建去重子列表列表:

from collections import Counter
list({frozenset(Counter(lst).items()): lst for lst in reversed(l1)}.values())[::-1]

這將返回:

[['The', 'quick', 'brown', 'fox'], ['hi', 'there'], ['jumps', 'over', 'the', 'lazy', 'dog']]

這個:

l1 = [['The', 'quick', 'brown', 'fox'], ['hi', 'there'], ['jumps', 'over', 'the', 'lazy', 'dog'], ['there', 'hi'], ['jumps', 'dog', 'over','lazy', 'the']]
s = {tuple(item) for item in map(sorted, l1)}
l2 = [list(item) for item in s]

l2 給出刪除了反向重復項的列表。 比較: 刪除列表中反向重復項的 Pythonic 方式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM