Каков «очевидный [...] способ» добавить все элементы итерируемого к существующему set
?
Каков «очевидный [...] способ» добавить все элементы итерируемого к существующему set
?
Ответы:
Вы можете добавить элементы list
к set
так:
>>> 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
конструктор принимает в качестве аргумента итерацию.
{1, 2, 3}
в Python 3, тогда как это было set([1, 2, 3])
в Python 2.
В интересах любого, кто может поверить, например, что выполнение aset.add()
в цикле будет иметь производительность, конкурентоспособную по сравнению с выполнением aset.update()
, вот пример того, как вы можете быстро проверить свои убеждения перед публикацией:
>\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
Похоже, что цена за элемент в циклическом подходе в три раза выше, чем в update
подходе.
Использование |= set()
стоит примерно в 1,5 update
раза больше, чем половина добавления каждого отдельного элемента в цикле.
Вы можете использовать функцию set (), чтобы преобразовать итерируемое в набор, а затем использовать стандартный оператор обновления набора (| =), чтобы добавить уникальные значения из вашего нового набора в существующий.
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
.update
Преимущество использования заключается в том, что аргумент может быть любым итеративным - не обязательно набором - в отличие от RHS |=
оператора в вашем примере.
|
для объединения, &
для пересечения и ^
для получения элементов, которые находятся в одном или другом, но не в обоих. Но в динамически типизированном языке, где иногда трудно читать код и знать типы объектов, летающих вокруг, я не решаюсь использовать эти операторы. Кто-то, кто их не распознает (или, возможно, даже не понимает, что Python допускает такие операторы), может быть сбит с толку и думать, что происходят какие-то странные побитовые или логические операции. Было бы хорошо, если бы эти операторы работали и на других итерируемых элементах ...
.update()
и добавил отдельные элементы в цикл. Нашел, что .update()
было быстрее. Я добавил свои результаты в этот существующий ответ: stackoverflow.com/a/4046249/901641
Просто быстрое обновление, время использования 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)
результаты:
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
Используйте понимание списка.
Короткое замыкание создания итерируемого с использованием списка, например :)
>>> 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])
>>>
[Изменить: пропустил заданную часть вопроса]
for item in items:
extant_set.add(item)
Для протокола, я думаю, что утверждение «Должен быть один - и желательно только один - очевидный способ сделать это». подделка Предполагается, что многие технические люди думают, что все думают одинаково. То, что очевидно для одного человека, не так очевидно для другого.
Я бы сказал, что предложенное мной решение легко читается и выполняет то, что вы просите. Я не верю, что с этим связаны какие-то проблемы с производительностью, хотя я допускаю, что я что-то упустил. Но, несмотря на все это, это может быть неочевидным и предпочтительным для другого разработчика.
aset.update(iterable)
зацикливается на скорости C, тогда как for item in iterable: aset.add(item)
зацикливается на скорости Python, с поиском метода и вызовом метода (aarrgghh !!) для каждого элемента.