Jaki jest „jeden [...] oczywisty sposób”, aby dodać wszystkie elementy iterowalne do istniejącego set
?
Jaki jest „jeden [...] oczywisty sposób”, aby dodać wszystkie elementy iterowalne do istniejącego set
?
Odpowiedzi:
Możesz dodać elementy a list
do set
takiego:
>>> 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 przyjmuje iterowalny argument jako argument.
{1, 2, 3}
W Pythonie 3, podczas gdy była set([1, 2, 3])
w Pythonie 2.
Z korzyścią dla każdego, kto mógłby wierzyć np., Że robienie aset.add()
w pętli mogłoby konkurować z działaniem aset.update()
, oto przykład, w jaki sposób można szybko sprawdzić swoje przekonania przed ujawnieniem się:
>\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
Wygląda na to, że koszt jednej pozycji w podejściu pętlowym jest TRZY razy większy niż w przypadku update
podejścia.
Korzystanie |= set()
kosztuje około update
1,5 raza więcej , ale połowę tego, co daje dodanie każdego pojedynczego elementu w pętli.
Możesz użyć funkcji set (), aby przekonwertować iterowalny zestaw na zestaw, a następnie użyć standardowego operatora aktualizacji zestawu (| =), aby dodać unikalne wartości z nowego zestawu do istniejącego.
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
.update
ma tę zaletę, że argument może być dowolnie iterowalny - niekoniecznie jako zbiór - w przeciwieństwie do prawej strony |=
operatora w twoim przykładzie.
|
dla unii, &
dla przecięcia i ^
dla pobrania elementów, które są w jednym lub drugim, ale nie w obu. Ale w dynamicznie wpisywanym języku, w którym czasami trudno jest odczytać kod i poznać typy obiektów latających dookoła, waham się, czy używać tych operatorów. Ktoś, kto ich nie rozpoznaje (a może nawet nie zdaje sobie sprawy, że Python dopuszcza takie operatory) może być zdezorientowany i pomyśleć, że mają miejsce jakieś dziwne operacje bitowe lub logiczne. Byłoby miło, gdyby ci operatorzy pracowali również nad innymi
.update()
i dodałem poszczególne elementy w pętli. Okazało się, że .update()
było szybsze. Dodałem moje wyniki do tej istniejącej odpowiedzi: stackoverflow.com/a/4046249/901641
Tylko szybka aktualizacja, czasy w Pythonie 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)
wyniki to:
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
Używaj rozumienia list.
Krótkie zwarcie tworzenia iterowalnego za pomocą listy, na przykład :)
>>> 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])
>>>
[Edytuj: brakowało części pytania]
for item in items:
extant_set.add(item)
Dla porządku, myślę, że stwierdzenie, że „Powinien istnieć jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego”. jest fałszywy. Zakłada, że wielu ludzi zorientowanych technicznie uważa, że wszyscy myślą podobnie. To, co jest oczywiste dla jednej osoby, nie jest takie oczywiste dla drugiej.
Twierdzę, że proponowane przeze mnie rozwiązanie jest czytelne i robi to, o co prosisz. Nie wierzę, że są z tym związane jakieś przeboje - chociaż przyznaję, że czegoś mi brakuje. Ale mimo wszystko może to nie być oczywiste i preferowane dla innego programisty.
aset.update(iterable)
zapętla się z prędkością C, podczas gdy for item in iterable: aset.add(item)
pętle z szybkością Pythona, z wyszukiwaniem metod i wywołaniem metody (aarrgghh !!) na element.