Быстрый способ расширения набора, если мы знаем, что элементы уникальны

Я выполняю несколько итераций типа:

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>, который должен быть быстрее на один или несколько порядков.