Sie müssen nicht beide list
s set
s konvertieren, nur eine. Ich denke, das Überspringen der unnötigen Umwandlung macht es lesbarer und eleganter.
Also, entweder:
set(a).intersection(b)
Oder:
s = set(a)
any(e in s for e in b)
Letzteres hat den Vorteil, kurzzuschließen, sobald es eine Übereinstimmung findet, und besser die Logik zum Ausdruck, und die Rückkehr True
oder False
statt einer nicht-falsch oder falsch set
, aber es ist zwei Zeilen statt einer, wenn das stört Sie. Ich habe keine Ahnung, ob dieser Vorteil die Kosten für das Einfügen der Schleife in einen Generatorausdruck anstatt in eine C-Funktion ausgleicht.
Performance-Ergebnisse mit list
s diese klein sind fast bedeutungslos, so lassen Sie uns dies versuchen:
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [375]: %timeit(set(a))
10000 loops, best of 3: 180 us per loop
In [376]: s=set(a) # since all versions need to do this
In [391]: %timeit(s & set(b))
1000000 loops, best of 3: 178 us per loop
In [392]: %timeit(s.intersection(b))
1000000 loops, best of 3: 247 us per loop
In [393]: %timeit(discard(e in s for e in b))
1000000 loops, best of 3: 550 ns per loop
In [394]: %timeit(any(e in s for e in b))
1000000 loops, best of 3: 749 ns per loop
In [395]: %timeit(any(e in a for e in b))
1000000 loops, best of 3: 1.42 us per loop
die Zahlen Um alle im Nanosekundenskala zu setzen, in den Kosten der set(a)
, dass alle, aber die letzten wieder hinzufügen benötigen, und vergleichen Sie die gleichen Tests von drei Python-Versionen (Apple-Aktie CPython 2.7.2, Python.org CPython 3.3.0, Homebrew PyPy 1.9.0/2.7.2, alle 64-Bit-Mac-Builds):
Nun, da ich darüber nachdenke, macht dies insgesamt Sinn. Die Chancen auf eine Kollision sind sehr hoch, so dass die Kosten für die Umwandlung des Ganzen in ein Set alles dominieren.
Das bedeutet, wir brauchen einen neuen Test mit 10000 eindeutigen Werten. Lassen Sie uns den Test mit diesem wiederholen:
In [29]: a, b = list(range(10000)), list(range(10000))
In [30]: random.shuffle(a)
In [31]: random.shuffle(b)
CP272 CP330 PyPy
s & set(b) 1277000 1168000 1141000
s.intersection(b) 1165000 1117000 2520000
discard(genexp) 1699000 1271000 770000
any(genexp) 389800 344543 320807
any(list-genexp) 62000 10400 1520
Diese sind vernünftiger. Und sie machen immer noch Sinn. Wenn Sie dieselben 10000 Elemente zufällig mischen, wie weit müssen Sie jeweils gehen? Nicht weit genug, um die Kosten von set
zu verdienen - eine der Listen lohnend zu machen, viel weniger beide!
Also, lassen Sie uns einen Fall versuchen, wo es keine Spiele:
In [43]: a=list(range(10000, 20000))
CP272 CP330 PyPy
s & set(b) 751000 770000 733000
s.intersection(b) 466000 530000 1920000
discard(genexp) 1246000 985000 749000
any(genexp) 1269000 966000 893000
any(list-genexp) 185000000 176000000 5870000
Ich habe keine Ahnung, wie PyPy das letzte tat so schnell, aber anders als das, hier keine Überraschungen.
Also, welches ist das beste?
Wenn Sie viele Kollisionen erwarten, sollten Sie es vermeiden, die Sätze wann immer möglich zu erstellen. Wenn Sie jedoch nur wenige Kollisionen erwarten, möchten Sie mindestens einen Satz erstellen. Wenn Sie keine Ahnung haben, denke ich, dass die sicherste Wette any(genexp)
ist - im schlimmsten Fall ist sie weniger als 3x so schlecht wie die beste, und wenn es eine Chance gibt, dass die Kollisionsrate hoch ist, wird sie viel schneller sein. Aber Sie können sich die Zahlen ansehen und selbst sehen.
Oder, besser natürlich, Zeit sie alle gegen echte Testdaten, die Sie erwarten zu begegnen.
Sind die Elemente innerhalb jeder Liste einzigartig? Wenn ja, können Sie das ganz einfach mit 'Sets' machen. –
Ja, die Elemente in einer Liste sind eindeutig. – Amyth
@Mike: Warte ... warum konntest du das nicht mit Sets machen, auch wenn die Elemente _weren't_ einmalig sind? Sie verlieren die Information, dass ein Element mehrere Male existiert, aber wenn Sie nur darauf achten, dass das Element existiert, haben Sie diese Information nicht benötigt. (Und wenn du es tust, könntest du immer einen 'Counter' anstelle eines' Sets' verwenden, um es zu behalten.) – abarnert