установить разницу производительности issubset в зависимости от типа аргумента - PullRequest
0 голосов
/ 06 июня 2018

почему этот вопрос?

Я пытался ответить на этот вопрос: Проверьте, существуют ли все значения в виде ключей в словаре с чем-то лучшим, чем сгенерированное понимание генераторана all (циклы python, даже в пониманиях, замедляют выполнение по сравнению с неявными циклами, выполняемыми некоторыми функциями):

all(i in bar for i in foo)

, где bar - словарь, а foo - список с использованиемset.issubset (с преобразованием в set из foo для возможности использования foo.issubset(bar)), и ему не удалось превзойти времена решения all (если оба контейнера не были преобразованы в sets).

мой вопрос:

Из документации set:

Примечание,неоператорные версии методов union (), intersection (), разности () иmmetric_difference (), issubset () и issperset () примут любую итерацию в качестве аргумента .Напротив, их операторные аналоги требуют, чтобы их аргументы были множествами.Это исключает подверженные ошибкам конструкции, такие как set ('abc') и 'cbs' в пользу более читабельного множества ('abc'). Intersection ('cbs').

Хорошо, но производительностьдействительно зависит от типа аргумента, даже если сложность этого не делает ( Сложность Python issubset () ):

import timeit
foo = {i for i in range(1, 10000, 2)}
bar = foo - {400}
n=10000
x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(set)",x)
x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'};foo=list(foo)",stmt="bar.issubset(foo)",number=n)
print("issubset(list)",x)
x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)};bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(dict)",x)
x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)}.keys();bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
print("issubset(dict_keys)",x)

мои результаты (Python 3.4):

issubset(set) 1.6141405847648826
issubset(list) 3.698748032058883
issubset(dict) 3.6300025109004244
issubset(dict_keys) 4.224299651223102

Таким образом, если в качестве аргумента передано set, результат будет очень быстрым.

Использование list намного медленнее.Я понял, что из-за хэша, который должен быть сделан на строках, это дорого.Поэтому я изменил свои тестовые входные данные с помощью целых чисел, таких как:

foo = {i for i in range(1, 10000, 2)}
bar = foo - {400}

, и результаты были глобально быстрее, но все еще огромная разница во времени:

issubset(set) 0.5981848205989139
issubset(list) 1.7991591232742143
issubset(dict) 1.889119736960271
issubset(dict_keys) 2.2531574114632678

Я также пытался изменить dictв dict.keys(), как и в Python 3, ключи называются (https://www.python.org/dev/peps/pep-3106/) «контейнерным или неупорядоченным контейнерным объектом».

Но в этом случае результат будет еще хуже, чем приdict или list.

Так почему же прохождение set бьется при прохождении list или dict или dict_keys объекта? Не знаюсм. что-либо упомянутое в документации об этом.

1 Ответ

0 голосов
/ 06 июня 2018

Алгоритм set.issubset требует работы с набором (количество заморозок и подклассов);если вы передадите ему что-то еще, он сделает набор.Это в основном all(elem in other for elem in self), и нужно знать, что elem in other эффективен и означает, что он означает для сетов.Единственный способ, которым он знает, как это гарантировать - это other набор.Создание набора стоит дорого.

(я замял некоторые детали. Если вы хотите точно знать, что происходит, особенно если у вас странный набор подклассов, прочитайте исходный код в ссылке.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...