Як додати вміст ітерабельного до набору?


Відповіді:


228

Ви можете додати елементи 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])

2
Я просто озирнувся на мій сеанс перекладача, і я насправді спробував це, але подумав, що він додав весь список як елемент набору через квадратні дужки у поданні набору. Я ніколи раніше не помічав, що вони представлені таким чином.
Ian Mackinnon

7
Таке представлення дозволяє вставити його прямо в інтерактивний сеанс, оскільки setконструктор приймає ітерабельний аргумент.
Френк Кустерс

3
Зауважте, що представництво є, наприклад, {1, 2, 3}у Python 3, тоді як воно було set([1, 2, 3])в Python 2.
Radon Rosborough

40

На користь тому, хто може повірити, наприклад, що те, що робити 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рази більше, ніж половина того, що додає кожен окремий елемент у циклі.


14

Ви можете використовувати функцію set () для перетворення ітерабельного набору в набір, а потім скористатися оператором оновлення стандартного набору (| =), щоб додати унікальні значення з нового набору в існуючий.

>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])

5
Використання .updateмає перевагу в тому, що аргумент може бути будь-яким ітерабельним - не обов'язково набором - на відміну від RHS |=оператора у вашому прикладі.
tzot

1
Гарна думка. Це просто естетичний вибір, оскільки set () може перетворити ітерабельний набір, але кількість натискань клавіш однакове.
gbc

Я ніколи не бачив цього оператора, мені сподобається його використовувати, коли він з’явиться в майбутньому; Дякую!
eipxen

1
@eipxen: Є |об'єднання, &для перетину та ^отримання елементів, що знаходяться в тому чи іншому, але не в обох. Але мовою, що динамічно набирається, де іноді важко читати код і знати типи об’єктів, що летять навколо, я не вагаюся використовувати ці оператори. Хтось, хто не розпізнає їх (або, можливо, навіть не усвідомлює, що Python дозволяє таким операторам), може бути розгублений і вважає, що відбуваються якісь дивні бітові або логічні операції. Було б добре, якби ці оператори також працювали над іншими ітерабелями ...
ArtOfWarfare

Проведіть кілька тестів на цей час .update()та додайте окремі елементи в циклі. Виявив, що .update()швидше. Я додав свої результати в цей існуючу відповідь: stackoverflow.com/a/4046249/901641
ArtOfWarfare

4

Просто швидке оновлення, таймінги за допомогою 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

0

Використовуйте розуміння списку.

Коротке замикання на створення ітерабельного, наприклад, за допомогою списку :)

>>> 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])
>>> 

[Редагувати: пропущено задану частину питання]


1
Я не бачу жодного набору? Я щось пропускаю?
Ian Mackinnon

-2
for item in items:
   extant_set.add(item)

Для запису я вважаю твердження, що "повинен бути один - і бажано лише один - очевидний спосіб зробити це". є фальшивим. Це припускає, що багато технічно налаштованих людей роблять, що всі думають однаково. Те, що є очевидним для однієї людини, не так очевидно для іншої.

Я б заперечував, що запропоноване нами рішення є читабельним і робить те, що ви просите. Я не вірю, що з цим пов’язані будь-які хіти виступу - хоча я визнаю, що я можу щось пропустити. Але, незважаючи на все це, це може бути не очевидним і кращим для іншого розробника.


Арг! Цикл for знаходиться в одному рядку, подібному до форматування моєї відповіді - я б ніколи цього не робив. Колись.
jaydel

Ви абсолютно праві. Я відредагував пост, щоб відшкодувати свою шкоду. Дякую :)
jaydel

9
Вам не вистачає точки, яка aset.update(iterable)циклізує зі швидкістю С, тоді як for item in iterable: aset.add(item)циклі на швидкості Python, з пошуком методу та викликом методу (aarrgghh !!) на елемент.
Джон Махін

1
Вибачте, він нічого не сказав про продуктивність у своєму запитанні, тому я не хвилювався з цього приводу.
jaydel
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.