Jak dodać zawartość iterowalnej do zestawu?

Odpowiedzi:

228

Możesz dodać elementy a listdo settakiego:

>>> 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
źródło
2
Po prostu spojrzałem wstecz na moją sesję z tłumaczem i faktycznie spróbowałem tego, ale pomyślałem, że dodało to całą listę jako element zestawu ze względu na nawiasy kwadratowe w reprezentacji zestawu. Nigdy wcześniej nie zauważyłem, że są tak reprezentowani.
Ian Mackinnon
7
Ta reprezentacja umożliwia wklejenie go z powrotem w sesji interaktywnej, ponieważ setkonstruktor przyjmuje iterowalny argument jako argument.
Frank Kusters,
3
Zauważ, że reprezentacja jest po prostu np. {1, 2, 3}W Pythonie 3, podczas gdy była set([1, 2, 3])w Pythonie 2.
Radon Rosborough
40

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 updatepodejścia.

Korzystanie |= set()kosztuje około update1,5 raza więcej , ale połowę tego, co daje dodanie każdego pojedynczego elementu w pętli.

John Machin
źródło
14

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])
gbc
źródło
5
Używanie .updatema tę zaletę, że argument może być dowolnie iterowalny - niekoniecznie jako zbiór - w przeciwieństwie do prawej strony |=operatora w twoim przykładzie.
tzot
1
Słuszna uwaga. To tylko wybór estetyczny, ponieważ set () może przekształcić iterowalny element w zestaw, ale liczba naciśnięć klawiszy jest taka sama.
gbc
Nigdy wcześniej nie widziałem tego operatora, z przyjemnością będę go używać, gdy pojawi się w przyszłości; dzięki!
eipxen
1
@eipxen: Jest |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
iterowalnymi
Przeprowadziłem kilka testów tego porównania .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
ArtOfWarfare
4

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
Daniel Dubovski
źródło
0

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]

pyfunc
źródło
1
Nie widzę żadnych zestawów? Czy coś mi brakuje?
Ian Mackinnon
-2
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.

jaydel
źródło
Argh! Pętla for znajdująca się w jednej linii jest formatowaniem w mojej odpowiedzi - nigdy bym tego nie zrobił. Zawsze.
jaydel
Masz całkowitą rację. Zredagowałem post, aby naprawić uszkodzenie. Dzięki :)
jaydel
9
Brakuje Ci punktu, który 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.
John Machin
1
Przepraszam, w swoim pytaniu nie powiedział nic o wydajności, więc nie martwiłem się tym.
jaydel