Создайте кортеж из наборов без дубликатов. - PullRequest
0 голосов
/ 07 марта 2019

Используя Python, я хотел бы сделать следующее ... создать кортеж наборов.Однако я хочу добавить набор в кортеж только в том случае, если он еще не существует в кортеже.Каждый набор представляет собой пару.Я использую наборы, потому что порядок пар не имеет значения.Я использую кортеж, потому что у меня более 1,5 строк данных для обработки, и кортеж быстрее для поиска, чем список.Я полагаю, что мне все еще нужно сделать некоторое понимание списка, но это один из моих вопросов.Мой первый вопрос: мой код не работает, как я могу это исправить?Мой второй вопрос: как я могу улучшить эффективность кода?

Я упростил этот пример, чтобы дать только основы.Каждый новый набор будет получен из источника данных и обработан.

my_tuple = ({"a", "b"}, {"c", "d"}, {"c", "e"})  # Existing tuple

new_set = {"b", "c"} # Get a set from data source

set_exists = any(new_set in a_set for a_set in my_tuple)
if not set_exists:
    my_tuple += (new_set,)

print(my_tuple)

({'a', 'b'}, {'c', 'd'}, {'c', 'e'}, {'b', 'c'})

Это хорошо.Набор не был в кортеже.

new_set = {"b", "a"} # Get a set from data source

set_exists = any(new_set in a_set for a_set in my_tuple)
if not set_exists:
    my_tuple += (new_set,)

print(my_tuple)

({'a', 'b'}, {'c', 'd'}, {'c', 'e'}, {'b', 'c'}, {'a', 'b'})

Не хорошо.Набор уже существовал в кортеже.Его не нужно было добавлять.

Большое спасибо за помощь.

Ответы [ 2 ]

3 голосов
/ 07 марта 2019

Состояние, которое вы должны проверять, гораздо проще, чем вы думаете:

set_exists = new_set in my_tuple

Ваш код должен работать с этим.

В любом случае, добавление к tuple равно медленно ;Если вы ищете производительность, ваш подход определенно не самый лучший.Улучшение заключается в использовании list, который имеет очень быстрые операции добавления, но, как и tuple, тесты членства также медленные.На самом деле, вопреки вашему убеждению, list и tuple практически одинаково медленны в поиске.

Решение состоит в том, чтобы использовать set из frozensets:

my_tuple = ({"a", "b"}, {"c", "d"}, {"c", "e"})

# convert to set, it's way faster!
# (this is a one-time operation, if possible, have your data in this format beforehand)
my_set = set(frozenset(s) for s in my_tuple)

# Again, if possible, get your data in the form of a frozenset so conversion is not needed
new_set = frozenset(("b", "c"))

if new_set not in my_set: # very fast!
    my_set.add(new_set)

new_set = frozenset(("a", "b"))

my_set.add(new_set) # the check is actually unneeded for sets

print(my_set)

Демо скоростей:

l = list(range(10 ** 6))
t = tuple(range(10 ** 6))
s = set(range(10 ** 6))

# Appending to tuple is slow!
%timeit global t; t += (1,)
11.4 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# Appending to list is fast!
%timeit l.append(1)
107 ns ± 6.43 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

# List and tuple membership tests are slow!
%timeit 500000 in l
5.9 ms ± 83.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit 500000 in t
6.62 ms ± 281 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# These operations are trivial for sets...
%timeit 500000 in s
73 ns ± 6.91 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1 голос
/ 07 марта 2019

Вы должны просто использовать набор наборов, ну frozenset , если быть точным, так как набор не является типом hashable:

my_set = {frozenset(["a", "b"]), frozenset(["c", "d"]), frozenset(["c", "e"])}
my_set.add(frozenset(["b", "a"]))
print(my_set)
# >>> set([frozenset(['c', 'e']), frozenset(['a', 'b']), frozenset(['c', 'd'])])
my_set.add(frozenset(["b", "z"]))
print(my_set)
# >>> set([frozenset(['c', 'e']), frozenset(['a', 'b']), frozenset(['b', 'z']), frozenset(['c', 'd'])])
...