(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