(Set) Понимание от нескольких значений

Предположим, у меня есть список l = [1,2,3] и я хочу создать набор всех чисел в этом списке и их квадратов. В идеале, в одном выражении понимания.

Лучшее, что я могу придумать, это (две итерации по списку):

set(_ for _ in l).union(_ * _ for _ in l)

2 ответа

Ваш собственный код может быть сокращен до:

set(l).union(x**2 for x in l)

в котором я переименовал _ в x, так как _ указывает значение не важно, но это так.

Строго говоря, вы все еще перебираете list дважды, но первый раз безоговорочно.

Если вы настаиваете на итерации один раз, вы получите это:

{y for x in l for y in (x, x**2)}

что является двойным пониманием, которое включает в себя следующее:

result = set()
for x in l:
    for y in (x, x**2):
        result.add(y)

ИМО, set(l + [i ** 2 for i in l]) это лучшее решение. Это яснее, чем понимание вложенного генератора.

И я сделал тест:

import timeit
l = list(range(5))
print(timeit.timeit("set(l + [_ ** 2 for _ in l])", 'from __main__ import ' + ', '.join(globals())))
print(timeit.timeit("{y for x in l for y in (x, x**2)}", 'from __main__ import ' + ', '.join(globals())))

выход:

3.0309128219996637
3.1958301850008866

Это показывает set(l + [i ** 2 for i in l]) немного быстрее Думаю, причина в том, что для понимания вложенного генератора необходимо создать внутренний объект. (x, x**2) для каждого цикла это замедляет

Обновить

import timeit
l = list(range(200000))
print(timeit.timeit("set(l + [_ ** 2 for _ in l])", 'from __main__ import ' + ', '.join(globals()), number=100))
print(timeit.timeit("{y for x in l for y in (x, x**2)}", 'from __main__ import ' + ', '.join(globals()), number=100))

выход:

16.46792753900081
19.72252997099895
Другие вопросы по тегам