Как получить элемент из множества без его удаления?
Вопрос о получении значения из множества в Python без удаления элемента
У меня есть следующая ситуация:
s = set([1, 2, 3])
Как я могу получить значение (любое значение) из множества s
, не используя метод s.pop()
? Я хочу оставить элемент в множестве до тех пор, пока не смогу его удалить – что я смогу сделать только после асинхронного вызова к другому хосту.
Вот временное решение:
elem = s.pop()
s.add(elem)
Но не можете ли вы предложить более эффективный способ? Я бы хотел, чтобы это выполнялось за константное время.
5 ответ(ов)
Два способа, которые не требуют копирования всего множества:
for e in s:
break
# e теперь является элементом из s
Или...
e = next(iter(s))
Однако в общем случае множества не поддерживают индексацию или срезы.
Наименьший код будет таким:
>>> s = set([1, 2, 3])
>>> next(iter(s))
1
Этот подход использует итератор, что позволяет избежать создания нового списка с элементами множества. Это будет более эффективно, особенно если ваше множество очень большое.
В ответ на ваш вопрос о сравнении различных подходов к итерации по множеству, я провел некоторые замеры времени для различных подходов и вот что у меня получилось.
Код, который я использовал, выглядит следующим образом:
from timeit import *
stats = ["for i in xrange(1000): iter(s).next() ",
"for i in xrange(1000): \n\tfor x in s: \n\t\tbreak",
"for i in xrange(1000): s.add(s.pop()) ",
"for i in xrange(1000): s.get() "]
for stat in stats:
t = Timer(stat, setup="s=set(range(100))")
try:
print "Time for %s:\t %f"%(stat, t.timeit(number=1000))
except:
t.print_exc()
Результаты выполнения кода:
$ ./test_get.py
Time for for i in xrange(1000): iter(s).next() : 0.433080
Time for for i in xrange(1000):
for x in s:
break: 0.148695
Time for for i in xrange(1000): s.add(s.pop()) : 0.317418
Time for for i in xrange(1000): s.get() : 0.146673
Из этих данных видно, что самый быстрый подход - это for/break. В некоторых случаях он работает даже быстрее, чем мой собственный метод get().
Если вам нужен случайный элемент, можно использовать следующий код:
>>> import random
>>> s = set([1, 2, 3])
>>> random.sample(s, 1)
[2]
Документация, похоже, не упоминает о производительности random.sample
. По проведенному быстрому эмпирическому тесту с большим списком и большим множеством кажется, что для списка это время постоянное, а для множества — нет. Также стоит отметить, что итерация по множеству не является случайной: порядок не определен, но предсказуем:
>>> list(set(range(10))) == range(10)
True
Если важна случайность и вам нужно получить несколько элементов за постоянное время (для больших множеств), я бы предложил использовать random.sample
, предварительно преобразовав множество в список:
>>> lst = list(s) # один раз, O(len(s))?
...
>>> e = random.sample(lst, 1)[0] # постоянное время
Еще один способ в Python 3:
next(iter(s))
или
s.__iter__().__next__()
Оба варианта позволяют получить следующий элемент итератора s
. Первый способ более распространён и читаем, поэтому его обычно предпочтительнее использовать.
Получить различия между двумя списками с уникальными элементами
Сохранить график в файл изображения вместо его отображения
Преобразование списка словарей в DataFrame pandas
Как отсортировать список/кортеж списков/кортежей по элементу на заданном индексе
Как отменить последнюю миграцию?