Was ist der "eine [...] offensichtliche Weg" , um alle Elemente eines iterablen zu einem vorhandenen hinzuzufügen set
?
Was ist der "eine [...] offensichtliche Weg" , um alle Elemente eines iterablen zu einem vorhandenen hinzuzufügen set
?
Antworten:
Sie können Elemente einer hinzufügen , list
um eine set
wie folgt aus :
>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])
set
Konstruktor eine Iterierbarkeit als Argument verwendet.
{1, 2, 3}
in Python 3 ist, während es set([1, 2, 3])
in Python 2 war.
Zum Wohle eines jeden, der könnte glauben , zB das zu tun aset.add()
in einer Schleife Leistung wettbewerbsfähig haben würde tun aset.update()
, hier ist ein Beispiel dafür , wie Sie Ihre Überzeugungen schnell , bevor sie der Öffentlichkeit testen:
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 294 usec per loop
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 950 usec per loop
>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 458 usec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 598 usec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 1.89 msec per loop
>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 891 usec per loop
Es sieht so aus, als ob die Kosten pro Element des Schleifenansatzes mehr als das DREIfache der Kosten des Ansatzes betragen update
.
Die Verwendung |= set()
kostet ungefähr das 1,5-fache update
der Leistung, aber die Hälfte der Kosten für das Hinzufügen jedes einzelnen Elements in einer Schleife.
Mit der Funktion set () können Sie ein iterables Element in ein Set konvertieren und dann mit dem Standard-Set-Update-Operator (| =) die eindeutigen Werte aus Ihrem neuen Set in das vorhandene Set einfügen.
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
.update
hat den Vorteil, dass das Argument im Gegensatz zur rechten Seite des |=
Operators in Ihrem Beispiel beliebig iterierbar sein kann - nicht unbedingt eine Menge .
|
für die Vereinigung, &
für die Kreuzung und ^
für das Abrufen von Elementen, die sich in dem einen oder anderen befinden, aber nicht in beiden. Aber in einer dynamisch typisierten Sprache, in der es manchmal schwierig ist, den Code zu lesen und die Arten von herumfliegenden Objekten zu kennen, zögere ich, diese Operatoren zu verwenden. Jemand, der sie nicht erkennt (oder vielleicht gar nicht merkt, dass Python solche Operatoren zulässt), könnte verwirrt sein und denken, dass einige seltsame bitweise oder logische Operationen ablaufen. Es wäre schön, wenn diese Operatoren auch an anderen
.update()
und fügen Sie einzelne Elemente in einer Schleife hinzu. Fand das .update()
war schneller. Ich habe meine Ergebnisse zu dieser vorhandenen Antwort hinzugefügt: stackoverflow.com/a/4046249/901641
Nur ein kurzes Update, Timings mit Python 3:
#!/usr/local/bin python3
from timeit import Timer
a = set(range(1, 100000))
b = list(range(50000, 150000))
def one_by_one(s, l):
for i in l:
s.add(i)
def cast_to_list_and_back(s, l):
s = set(list(s) + l)
def update_set(s,l):
s.update(l)
Ergebnisse sind:
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
Verwenden Sie das Listenverständnis.
Kurzschließen der Erstellung von iterable anhand einer Liste zum Beispiel :)
>>> x = [1, 2, 3, 4]
>>>
>>> k = x.__iter__()
>>> k
<listiterator object at 0x100517490>
>>> l = [y for y in k]
>>> l
[1, 2, 3, 4]
>>>
>>> z = Set([1,2])
>>> z.update(l)
>>> z
set([1, 2, 3, 4])
>>>
[Bearbeiten: den festgelegten Teil der Frage verpasst]
for item in items:
extant_set.add(item)
Für die Aufzeichnung denke ich die Behauptung, dass "es einen - und vorzugsweise nur einen - offensichtlichen Weg geben sollte, dies zu tun." ist falsch. Es wird davon ausgegangen, dass viele technisch denkende Menschen davon ausgehen, dass jeder gleich denkt. Was für eine Person offensichtlich ist, ist für eine andere Person nicht so offensichtlich.
Ich würde argumentieren, dass meine vorgeschlagene Lösung klar lesbar ist und das tut, was Sie verlangen. Ich glaube nicht, dass es irgendwelche Performance-Hits gibt - obwohl ich zugeben muss, dass mir etwas fehlt. Trotz alledem ist dies möglicherweise nicht offensichtlich und einem anderen Entwickler vorzuziehen.
aset.update(iterable)
mit C-Geschwindigkeit for item in iterable: aset.add(item)
wiederholt wird, während Schleifen mit Python-Geschwindigkeit ausgeführt werden, mit einer Methodensuche und einem Methodenaufruf (aarrgghh !!) pro Element.