Який "очевидний спосіб [...]" додати всі елементи ітерабельності до існуючих 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)
циклізує зі швидкістю С, тоді як for item in iterable: aset.add(item)
циклі на швидкості Python, з пошуком методу та викликом методу (aarrgghh !!) на елемент.