Wie füge ich den Inhalt einer Iterable zu einem Set hinzu?

Antworten:

228

Sie können Elemente einer hinzufügen , listum eine setwie 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])
SingleNegationElimination
quelle
2
Ich habe gerade auf meine Dolmetschersitzung zurückgeschaut und dies tatsächlich versucht, dachte aber, dass die gesamte Liste aufgrund der eckigen Klammern in der Darstellung des Satzes als Element des Satzes hinzugefügt wurde. Ich hatte noch nie bemerkt, dass sie so dargestellt werden.
Ian Mackinnon
7
Mit dieser Darstellung können Sie sie direkt wieder in eine interaktive Sitzung einfügen, da der setKonstruktor eine Iterierbarkeit als Argument verwendet.
Frank Kusters
3
Beachten Sie, dass die Darstellung nur zB {1, 2, 3}in Python 3 ist, während es set([1, 2, 3])in Python 2 war.
Radon Rosborough
40

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 updateder Leistung, aber die Hälfte der Kosten für das Hinzufügen jedes einzelnen Elements in einer Schleife.

John Machin
quelle
14

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])
gbc
quelle
5
Die Verwendung .updatehat den Vorteil, dass das Argument im Gegensatz zur rechten Seite des |=Operators in Ihrem Beispiel beliebig iterierbar sein kann - nicht unbedingt eine Menge .
Zot
1
Guter Punkt. Dies ist nur eine ästhetische Entscheidung, da set () ein iterables Element in ein Set konvertieren kann, die Anzahl der Tastenanschläge jedoch gleich ist.
GBC
Ich habe diesen Operator noch nie gesehen. Ich werde ihn gerne verwenden, wenn er in Zukunft angezeigt wird. Vielen Dank!
Eipxen
1
@eipxen: Es gibt |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
Iterables arbeiten würden
Führen Sie einige Zeittests durch .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
ArtOfWarfare
4

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
Daniel Dubovski
quelle
0

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]

pyfunc
quelle
1
Ich sehe keine Sets? Vermisse ich etwas
Ian Mackinnon
-2
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.

Jaydel
quelle
Argh! Die for-Schleife in einer solchen Zeile wird in meiner Antwort formatiert - das würde ich niemals tun. Je.
Jaydel
Sie sind absolut richtig. Ich habe den Beitrag bearbeitet, um meinen Schaden zu reparieren. Danke :)
Jaydel
9
Sie vermissen den Punkt, der 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.
John Machin
1
Entschuldigung, er hat in seiner Frage nichts über die Leistung gesagt, also habe ich mir darüber keine Sorgen gemacht.
Jaydel