2009-09-30 6 views
8

Ich habe eine Liste in Python, die ich als Teil des Programms erzeuge. Ich habe eine starke Annahme, dass diese alle verschieden sind, und ich überprüfe dies mit einer Behauptung.Was ist der pythischste Weg, um sicherzustellen, dass alle Elemente einer Liste unterschiedlich sind?

Dies ist die Art, wie ich es jetzt tun:

Wenn es zwei Elemente sind:

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

Wenn es drei:

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") 

Und wenn ich jemals das tun mit vier Elementen werde ich verrückt.

Gibt es einen besseren Weg, um sicherzustellen, dass alle Elemente der Liste eindeutig sind?

Antwort

26

Vielleicht so etwas wie:

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

Sehr kluge Antwort – foosion

+2

Sie sie einfach in einem Satz in erster Linie speichern könnte, um sicherzustellen, dass sie alle einzigartig sind. Oder speichern Sie sie in einem Set, aber überprüfen Sie vor dem Hinzufügen zum Set die Mitgliedschaft. Aber das funktioniert definitiv, wenn Sie das Eingabeformat nicht kontrollieren können. –

+0

Sätze müssen nicht unbedingt die Reihenfolge beibehalten, was wichtig sein könnte. –

7

Wie wäre es damit:

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

Dies setzt voraus, dass die Elemente in x hashable sind.

2

Hoffentlich sind alle Elemente in Ihrer Sequenz unveränderlich - wenn nicht, können Sie set auf der Sequenz nicht aufrufen.

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

Wenn Sie tun haben veränderbare Elemente, können Sie nicht die Einzelteile Hash und Sie werden ziemlich viel haben immer wieder durch die Liste überprüfen:

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

Beim Erstellen der Liste können Sie prüfen, ob der Wert bereits existiert, z. B .:

if x in y: 
    raise Exception("Value %s already in y" % x) 
else: 
    y.append(x) 

Der Vorteil besteht darin, dass die kollidierende Variable gemeldet wird.

0

Man könnte die Liste verarbeiten erstellen bekannt sein-Unikat:

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))) 

Oder wenn die seq Elemente nicht hashable:

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

Und die Einzelteile halten in Ordnung (natürlich ohne Duplikate).

18

Die beliebtesten Antworten sind O (N) (gut! -), aber wie @Paul und @Mark herausstellen, erfordern sie, dass die Einträge der Liste hashbar sind. Sowohl @Paul als auch @ Marks vorgeschlagene Ansätze für nicht hashbare Elemente sind allgemein, aber nehmen O (N-Quadrat) - d. H. Eine Menge.

Wenn die Artikel Ihrer Liste nicht hashbar sind, aber sind vergleichbar, können Sie es besser machen ... hier ist ein Ansatz, der immer so schnell wie möglich funktioniert angesichts der Art der Liste der Elemente.

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)) 

Dies ist O (N), wo möglich (alle Artikel hashable), O (N log N) als häufigste Rückfall (einige Elemente unhashable, aber vergleichbar), O (N zum Quadrat), wo unvermeidlich (einige Gegenstände nicht abspülbar, z. B. dicts und einige nicht vergleichbare, z. B. komplexe Zahlen).

Inspiration für diesen Code stammt aus einem alten Rezept der großen Tim Peters, die tatsächlich unterschied sich durch eine Liste von Unikaten produzieren (und war auch so weit vor, dass set nicht da war - es hat eine dict verwenden musste. ..! -), aber grundsätzlich mit identischen Problemen konfrontiert.

+0

Ich vermisse Tim. Muss ihn bald wieder zum Mittagessen einladen. – holdenweb

+0

Heh, ich vermisse ihn mehr (es ist länger gewesen!), Aber ich denke, es ist irgendwie unpraktisch für uns beide, nur für ein Mittagessen von Küste zu Küste zu fliegen ;-). –

+0

Meinst du 'v nicht in L [i + 1:] für v, i in enumerate (L)'? – chepner

0

würde ich verwenden:

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

'O (n ** 2)', ist das nicht? – SilentGhost

Verwandte Themen