2009-09-30 6 views
8

Mam listę w języku Python, które generuję jako część programu. Mam silne przypuszczenie, że wszystkie są różne i sprawdzam to za pomocą twierdzenia.Jaki jest najbardziej pythonic sposób, aby upewnić się, że wszystkie elementy listy są różne?

ten sposób zrobić to teraz:

Jeśli istnieją dwa elementy:

try: 
    assert(x[0] != x[1]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

Jeśli są trzy:

try: 
    assert(x[0] != x[1]) 
    assert(x[0] != x[2]) 
    assert(x[1] != x[2]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

I jeśli kiedykolwiek musiał to zrobić z czterema elementami oszaleję.

Czy istnieje lepszy sposób na zapewnienie, że wszystkie elementy listy są niepowtarzalne?

Odpowiedz

26

Może coś takiego:

if len(x) == len(set(x)): 
    print "all elements are unique" 
else: 
    print "elements are not unique" 
+0

Bardzo mądra odpowiedź – foosion

+2

Po prostu mógł je przechowywać w zestawie w pierwszej kolejności, aby upewnić się, że wszystkie one są unikalne. Lub zapisz je w zestawie, ale przed dodaniem do zestawu sprawdź członkostwo. Ale to na pewno działa, jeśli nie masz kontroli nad formatem wejściowym. –

+0

zestawy niekoniecznie zachowują kolejność, która może być ważna. –

7

Jak ten temat:

if len(x) != len(set(x)): 
    raise Exception("throw to caller") 

ta zakłada, że ​​elementy x są hashable.

2

Mam nadzieję, że wszystkie pozycje w sekwencji są niezmienne - jeśli nie, nie będzie można zadzwonić pod numer set w sekwencji.

>>> set(([1,2], [3,4])) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

Jeśli zrobić mają zmienne elementy, nie można hash elementów i będzie dość dużo trzeba wielokrotnie sprawdzić listę:

def isUnique(lst): 
    for i,v in enumerate(lst): 
     if v in lst[i+1:]: 
      return False 
    return True 

>>> isUnique(([1,2], [3,4])) 
True 
>>> isUnique(([1,2], [3,4], [1,2])) 
False 
1

Podczas tworzenia listy możesz sprawdzić, czy ta wartość już istnieje, np .:

korzyścią jest to, że zostanie zgłoszona zmienna zderzeniowa.

0

Można przetwarzać listę, aby utworzyć wiadomo-do-niepowtarzalnym egzemplarzu:

def make_unique(seq): 
    t = type(seq) 
    seen = set() 
    return t(c for c in seq if not (c in seen or seen.add(c))) 

Albo jeśli elementy seq nie są hashable:

def unique1(seq): 
    t = type(seq) 
    seen = [] 
    return t(c for c in seq if not (c in seen or seen.append(c))) 

I to będzie utrzymywać pozycje w kolejności (oczywiście bez duplikatów).

18

Najpopularniejszymi odpowiedziami są O (N) (dobrze! -), ale, jak zaznaczają @Paul i @Mark, wymagają, aby elementy listy były nieosiągalne. Zarówno proponowane podejścia @Paul, jak i @ Mark do nieuszkodzonych przedmiotów są ogólne, ale przyjmują O (N do kwadratu) - tj. Dużo.

Jeśli pozycje na liście nie dają się przetłumaczyć, ale porównywalne, można zrobić lepiej ... oto podejście, które zawsze działa tak szybko, jak to możliwe, biorąc pod uwagę charakter elementów listy.

import itertools 

def allunique(L): 
    # first try sets -- fastest, if all items are hashable 
    try: 
    return len(L) == len(set(L)) 
    except TypeError: 
    pass 
    # next, try sort -- second fastest, if items are comparable 
    try: 
    L1 = sorted(L) 
    except TypeError: 
    pass 
    else: 
    return all(len(list(g))==1 for k, g in itertools.groupby(L1)) 
    # fall back to the slowest but most general approach 
    return all(v not in L[i+1:] for i, L in enumerate(L)) 

Jest to O (N), gdzie to możliwe (wszystkie pozycje hashable), O (N log N) jako najczęstsza awaryjnej (niektóre elementy unhashable, ale porównywalne), O (N kwadratu), gdzie nieuniknione (niektóre elementy nie nadające się do użytku, np. dyktuje, a niektóre nieporównywalne, np. liczby zespolone).

Inspiracja dla tego kodu pochodzi ze starej receptury autorstwa wielkiego Tima Petersa, która różniła się tym, że rzeczywiście tworzy listę unikatowych przedmiotów (a także było tak dawno temu, że w pobliżu nie było set - musiało użyć dict. ..! -), ale zasadniczo napotkał identyczne problemy.

+0

Tęsknię za Timem. Musi wkrótce zaprosić go na lunch. – holdenweb

+0

Heh, tęsknię za nim więcej (to już dłużej!), Ale myślę, że jest to niepraktyczne dla każdego z nas, aby lecieć od brzegu do brzegu tylko na lunch ;-). –

+0

Czy miałeś na myśli 'v nie w L [i + 1:] dla v, i w wyliczeniu (L)'? – chepner

0

użyłbym to:

mylist = [1,2,3,4] 
is_unique = all(mylist.count(x) == 1 for x in mylist) 
+0

'O (n ** 2)', nie jest? – SilentGhost