2015-06-01 15 views
14

sagen, dass ich verschiedene Sätze haben (sie haben, anders zu sein, ich kann sie nicht beitreten gemäß der Art der Daten, mit denen ich arbeite):Wie kann man überprüfen, ob ein Wert in einem gegebenen Mengen vorhanden ist

r = set([1,2,3]) 
s = set([4,5,6]) 
t = set([7,8,9]) 

Was ist der beste Weg zu überprüfen, ob eine Variable in einem von ihnen vorhanden ist?

Ich verwende:

if myvar in r \ 
    or myvar in s \ 
    or myvar in t: 

Aber ich frage mich, ob dies durch die Verwendung set ‚s Eigenschaften wie union irgendwie reduziert werden kann.

Die folgenden Werke, aber ich finde keine Möglichkeit, mehrere Gewerkschaften zu definieren:

if myvar in r.union(s) 
    or myvar in t: 

Und ich frage mich auch, wenn diese Verbindung irgendwie Leistung auswirken wird, da ich eine vorübergehende set erraten erstellt werden im laufenden Betrieb

+0

Ich kenne den Titel „Wie kann man überprüfen, ob ein Wert vorhanden ist, in einem gegebenen Mengen“ ein bisschen komisch klingt. Wenn jemand eine bessere Möglichkeit sieht, es zu schreiben, können Sie es gerne bearbeiten! – fedorqui

Antwort

13

Nur jeder verwenden:

if any(myvar in x for x in (r,s,t)) 

Satz Lookups 0(1) so eine Union zu schaffen, in jedem Satz zu überprüfen, ob die Variable ist völlig unnötig ist anstatt einfach in mit any zu überprüfen, was einen Kurzschluss verursacht, sobald eine Übereinstimmung gefunden wird, und keinen neuen Satz erstellt.

Und ich frage mich auch, wenn diese Verbindung irgendwie Leistung beeinflussen

Ja natürlich unioning die Sätze beeinflusst die Leistung, es auf die Komplexität hinzufügt, werden Sie jedes Mal einen neuen Satz zu schaffen, die O(len(r)+len(s)+len(t)) ist, so dass Sie kann sich von dem wirklichen Punkt verabschieden, Sets zu verwenden, die effiziente Lookups sind.

So lautet das Fazit ist, dass es Ihnen eine effiziente Lookups behalten möchten Sie den Satz einmal Vereinigung haben und sie in Erinnerung behalten eine neue Variable zu schaffen dann, dass mit Ihrer Suche für myvar so die anfängliche Schöpfung sein zu tun 0(n) und Lookups werden danach 0(1) sein.

Wenn Sie nicht jedes Mal, wenn Sie eine Suche zuerst die Vereinigung erstellen möchten, haben Sie eine lineare Lösung in der Länge von r+s+t -> set.union(*(r, s, t)) im Gegensatz zu im schlimmsten Fall drei konstante (im Durchschnitt) Lookups. Das bedeutet auch immer Elemente aus dem neuen unioned set hinzuzufügen oder zu entfernen, die aus r,s oder t hinzugefügt/entfernt werden.

Einige realistische Timings auf mäßig großformatigen Sätze zeigen genau den Unterschied:

In [1]: r = set(range(10000)) 

In [2]: s = set(range(10001,20000)) 

In [3]: t = set(range(20001,30000)) 

In [4]: timeit any(29000 in st for st in (r,s,t)) 
1000000 loops, best of 3: 869 ns per loop 

In [5]: timeit 29000 in r | s | t 
1000 loops, best of 3: 956 µs per loop 

In [6]: timeit 29000 in reduce(lambda x,y :x.union(y),[r,s,t]) 
1000 loops, best of 3: 961 µs per loop 

In [7]: timeit 29000 in r.union(s).union(t) 
1000 loops, best of 3: 953 µs per loop 

die Vereinigung zeigt Zeit, dass so ziemlich die ganze Zeit in der Union Anrufe ausgegeben:

In [8]: timeit r.union(s).union(t) 
1000 loops, best of 3: 952 µs per loop 

größer Verwendung Setzt und holt das Element in den letzten Satz:

In [15]: r = set(range(1000000)) 

In [16]: s = set(range(1000001,2000000)) 

In [17]: t = set(range(2000001,3000000)) 


In [18]: timeit any(2999999 in st for st in (r,s,t)) 
1000000 loops, best of 3: 878 ns per loop 

In [19]: timeit 2999999 in reduce(lambda x,y :x.union(y),[r,s,t]) 
1 loops, best of 3: 161 ms per loop 

In [20]: timeit 2999999 in r | s | t 
10 loops, best of 3: 157 ms per loop 

Es gibt l iterally kein Unterschied, egal wie groß die Sätze werden mit any aber wie die eingestellten Größen wächst auch die Laufzeit mit Union.

Der einzige Weg, um es schneller zu or halten wäre, aber wir den Unterschied von einigen hundert Nanosekunden einnehmen, die die Kosten für die Erstellung des Generators Ausdruck und den Funktionsaufruf ist:

In [22]: timeit 2999999 in r or 2999999 in s or 2999999 in t 
10000000 loops, best of 3: 152 ns per loop 

zu Vereinigungsmengen set.union (* (r, s, t)) ist auch die schnellsten, wie Sie bauen keine Vermittler-Sets:

In [47]: timeit 2999999 in set.union(*(r,s,t)) 
10 loops, best of 3: 108 ms per loop 
In [49]: r | s | t == set.union(*(r,s,t)) 
Out[49]: True 
+0

Also ist die Leistung sehr schlecht, wenn ich 'union' verwende, während 'any()' schneller ist? – fedorqui

+0

@fedorqui, wenn Sie einen Satz erstellen, ist es '0 (n)' n offensichtlich die Länge Ihres Satzes. Wenn Sie dies jedes Mal tun müssen, wenn Sie nach myvar suchen wollen, müssen Sie nun ein Set erstellen, bei dem die Länge von 'r + s + t 'immer überschritten wird, bevor Sie einen Lookup durchführen any' ist jetzt eine lineare Operation. –

+0

@fedorqui mit irgendwelchen ist ein gutes Rezept, aber in diesem Fall ist 'Wert in r | s | t' schneller! Kasse meine Antwort für Benchmark! – Kasramvd

4

Sie reduce Funktion anwenden Funktion zweier Argumente kumulativ auf die Elemente von iterable verwenden:

>>> r = set([1,2,3]) 
>>> s = set([4,5,6]) 
>>> t = set([7,8,9]) 
>>> 
>>> reduce(lambda x,y :x.union(y),[r,s,t]) 
set([1, 2, 3, 4, 5, 6, 7, 8, 9]) 

Und zur Überprüfung der Mitgliedschaft in einer von ihnen Sie einen Generator Ausdruck innerhalb any verwenden können, ist effizienter hier, weil Python verwenden hash table zum Speichern der Sätze und die Überprüfung der Mitgliedschaft hat O (1) in solchen Datenstrukturen wie Wörterbücher oder frozenset .Auch für die Prüfung der Mitgliedschaft in allen von Ihnen verwenden Sie all.

if any(i in item for item in [r,s,t]): 
    #do stuff 

Aber in diesem Fall (nicht für große Mengen) or Operator ist schneller.

value in r|s|t 

Dies ist ein Maßstab auf allen Wegen:

~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in reduce(lambda x,y :x.union(y),[r,s,t])" 
1000000 loops, best of 3: 1.55 usec per loop 
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in r|s|t" 
1000000 loops, best of 3: 1.11 usec per loop 
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);any(3 in item for item in [r,s,t])" 
1000000 loops, best of 3: 1.24 usec per loop 
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in r.union(s).union(t)" 
1000000 loops, best of 3: 1.19 usec per loop 

Hinweis dass als @Padraic Cunningham erwähnt für große Mengen ein any mit sehr viel effizienter!

+1

Das Erstellen des Generatorausdrucks und des Funktionsaufrufs erfordert wahrscheinlich mehr Zeit als alles. Testen von drei 3-Element-Sätzen liefert kein genaues Bild davon, wie ineffizient es für die Vereinigung ist. - –

+0

Danke, dass du mir die 'reduce' Funktion gezeigt hast, wusste nicht davon. Behalte es für zukünftige Referenz im Gedächtnis :) – fedorqui

+0

@PadraicCunningham in der Tat, dass es so ist, wie in meiner Antwort gesagt wird, nur für ** diesen Fall ** irgendwie muss ich sagen, dass für große Sätze 'any' besser ist.i ' Ich füge es meiner Antwort hinzu. Danke auch für das Zeigen! – Kasramvd

14

können Sie builtin any verwenden:

r = set([1,2,3]) 
s = set([4,5,6]) 
t = set([7,8,9]) 
if any(myvar in x for x in [r,s,t]): 
    print "I'm in one of them" 

any wird Kurzschluss auf der ersten Bedingung, die True liefert so können Sie rund um einen potenziell riesigen union oder Überprüfung potenziell viele Sätze für die Aufnahme erhalten zu konstruieren.

Und ich frage mich auch, ob diese Verbindung irgendwie Leistung beeinflussen wird, da ich denke, ein temporäres Set wird im laufenden Betrieb erstellt werden.

Nach wiki.python.coms|t ist während Lookups O(1) sind.

Für n Sets mit l Elemente je tun union iterativ den Satz zu konstruieren, führen zu:

a.union(b).union(c).union(d) .... .union(n) 

die zu O(l+l) für a.union(b) entspricht und O(2l+2l+l)a.union(b).union(c) und so weiter, die Beträge zu O(n*(n+1)/2)*l) auf.

O(n^2*l) ist quadratisch und macht den Leistungsvorteil der Verwendung von Sets zunichte.

Das Nachschlagen in n Sätzen mit any wird bei führen O(n)

+0

Ich bin auch sehr dankbar für Ihre Antwort. Es ist schade, dass so viele gute Antworten in der gleichen Frage erschienen, ich würde sie alle gerne akzeptieren :) – fedorqui

+0

FWIW, "union" ist variadisch, was die Kette (und asymptotische Zeiten) vereinfachen kann. – Veedrac

2

Sie können einfach tun

Und Sie müssen sich hier keine Gedanken über die Leistung machen. Ja, es erstellt ein temporäres Set im laufenden Betrieb, aber da es nicht gespeichert wird, wird Müll gesammelt.

+0

Interessant! So wird es Müll gesammelt werden, sobald es überprüft wird. – fedorqui

+0

@fedorqui Ja, sobald keine Referenzen auf das erstellte Objekt vorhanden sind, wird Müll gesammelt. Und in diesem Fall, da die Union in keiner Variablen gespeichert ist, gibt es nach dem Aufruf der Anweisung keine Verweise darauf. – Alfie

+4

Wenn die meisten Leute "Leistung" sagen, meinen sie Geschwindigkeit. – OrangeDog

4

| ist ein Union Operator von sets in Python. Sie können union über mehrere Sätze definieren mit | als:

>>> r = set([1,2,3]) 
>>> s = set([4,5,6]) 
>>> t = set([7,8,9]) 
>>> r | s | t 
set([1, 2, 3, 4, 5, 6, 7, 8, 9]) 
+1

Also 'r | s | t 'ist der Weg, mehrere' Vereinigungen 'zusammen zu haben. Danke dafür! – fedorqui

Verwandte Themen