Быстрый способ расширения набора, если мы знаем, что элементы уникальны
Я выполняю несколько итераций типа:
masterSet=masterSet.union(setA)
По мере увеличения набора времени, затрачиваемого на выполнение этих операций, растет (как и следовало ожидать, я думаю).
Я ожидаю, что пришло время проверить, находится ли каждый элемент setA уже в masterSet?
Мой вопрос в том, что если я ЗНАЮ, что masterSet уже не содержит каких-либо элементов в setA, могу ли я сделать это быстрее?
[ОБНОВЛЕНИЕ]
Учитывая, что этот вопрос все еще привлекает взгляды, я подумал, что я проясню некоторые вещи из комментариев и ответов ниже:
При повторении, хотя было много итераций, где я знал setA
, был бы отличным от masterSet
из-за того, как он был создан (без обработки каких-либо проверок), но несколько итераций, которые мне нужны проверка уникальности.
Я задавался вопросом, есть ли способ "рассказать" процедуру masterSet.union()
, чтобы не беспокоиться об однозначной проверке на этот раз, поскольку я знаю, что этот отличается от masterSet
, просто добавьте эти элементы, быстро доверяя утверждению программиста, которые они были definately distict. Perhpas посредством вызова какой-то другой процедуры ".unionWithDistinctSet()
" или чего-то еще.
Я думаю, что ответы предположили, что это невозможно (и что действительно установленные операции должны быть достаточно быстрыми в любом случае), но использовать masterSet.update(setA)
вместо объединения, поскольку это немного быстрее.
Я принял самый ясный ответ по этим направлениям, разрешил вопрос, который у меня был в то время, и продолжил свою жизнь, но все равно хотел бы услышать, может ли когда-нибудь существовать моя гипотеза .unionWithDistinctSet()
?
Ответы
Ответ 1
Вы можете использовать set.update
, чтобы обновить свой основной набор. Это экономит выделение нового набора все время, поэтому оно должно быть немного быстрее, чем set.union
...
>>> s = set(range(3))
>>> s.update(range(4))
>>> s
set([0, 1, 2, 3])
Конечно, если вы делаете это в цикле:
masterSet = set()
for setA in iterable:
masterSet = masterSet.union(setA)
Вы можете повысить производительность, выполнив что-то вроде:
masterSet = set().union(*iterable)
В конечном счете, тестирование членства в наборе - O (1) (в среднем случае), поэтому тестирование, если элемент уже содержится в наборе, на самом деле не является большим успехом.
Ответ 2
Если вы знаете, что ваши элементы уникальны, набор не обязательно является лучшей структурой.
Простой список быстрее распространяется.
masterList = list(masterSet)
masterList.extend(setA)
Ответ 3
Как указывает Мимилсон, вы можете использовать update
для обновления набора на месте с другого набора. Это работает немного быстрее:
def union():
i = set(range(10000))
j = set(range(5000, 15000))
return i.union(j)
def update():
i = set(range(10000))
j = set(range(5000, 15000))
i.update(j)
return i
timeit.Timer(union).timeit(10000) # 10.351907968521118
timeit.Timer(update).timeit(10000) # 8.83384895324707
Ответ 4
Конечно, отказ от этой проверки может быть большой экономией, когда метод __eq__(..)
очень дорог. В реализации CPython __eq__(..)
вызывается с каждым элементом, уже установленным в хэши, с тем же номером. (Ссылка: исходный код для set
.)
Однако эта функция никогда не будет реализована за миллион лет, потому что она открывает другой способ нарушить целостность набора. Проблема, связанная с этим, намного превосходит (обычно незначительное) увеличение производительности. Хотя, если это определяется как узкое место в производительности, нетрудно написать расширение С++ и использовать его STL <set>
, который должен быть быстрее на один или несколько порядков.