2009-10-24 1 views
42

Недавно я столкнулся с сценарием, в котором, если набор содержит только один элемент, я хотел что-то сделать с этим элементом. Чтобы получить элемент, я остановился на этом подходе:Как извлечь член из однопользовательского набора в python?

element = list(myset)[0] 

Но это не очень приятно, так как это создает ненужный список. Это также можно сделать с помощью итерации, но итерация кажется неестественной, так как существует только один элемент. Я что-то пропустил?

ответ

62

набор для распаковки.

(element,) = myset 

(Кстати, Python-DEV исследовал, но отклонил добавление myset.get() для возврата произвольного элемента из набора. Discussion here, Гвидо ван Россум отвечает 1 и 2.)

Мой личный фаворит для получения произвольного элемента является (если у вас есть неизвестное число, но также работает, если у вас есть только один):

element = next(iter(myset)) ¹ 

: в Python 2.5 и Befor е, вы должны использовать iter(myset).next()

+6

Очень приятно! Мне нравится, что это терпит неудачу, если количество элементов не равно 1. –

+0

@Laurence: Это прекрасное наблюдение. Поймать ошибки рано, правда? – u0b34a0f6ae

+2

Или, если вы хотите притвориться, что у Python есть правильный оператор для работы (ваши коллеги будут вас ненавидеть): 'element, = myset' – rdb

2

вы можете использовать element = tuple(myset)[0], который является немного более эффективным, или, вы можете сделать что-то вроде

element = iter(myset).next() 

Я думаю, построив итератор является более эффективным, чем строительство кортежа/списка ,

+0

Почему вы предполагаете, что создание итератора более эффективно? –

+0

к счастью, я указываю вам ответ Алекса :) –

17

Между делает кортеж и сделать итератор, это почти мыть, но итерация победа носа ...:

$ python2.6 -mtimeit -s'x=set([1])' 'a=tuple(x)[0]' 
1000000 loops, best of 3: 0.465 usec per loop 
$ python2.6 -mtimeit -s'x=set([1])' 'a=tuple(x)[0]' 
1000000 loops, best of 3: 0.465 usec per loop 
$ python2.6 -mtimeit -s'x=set([1])' 'a=next(iter(x))' 
1000000 loops, best of 3: 0.456 usec per loop 
$ python2.6 -mtimeit -s'x=set([1])' 'a=next(iter(x))' 
1000000 loops, best of 3: 0.456 usec per loop 

Не знаю, почему все ответы используют старший синтаксис iter(x).next(), а не новый next(iter(x)), который кажется мне предпочтительным (а также работает в Python 3.1).

Однако распаковка выигрывает руки вниз по обоим:

$ python2.6 -mtimeit -s'x=set([1])' 'a,=x' 
10000000 loops, best of 3: 0.174 usec per loop 
$ python2.6 -mtimeit -s'x=set([1])' 'a,=x' 
10000000 loops, best of 3: 0.174 usec per loop 

Это, конечно, для множеств с одним пунктом (где последняя форма, как и другие упомянутые, имеет то преимущество, что не суметь быстро, если набор вы «знал», что на самом деле у одного предмета было несколько). Для множеств с произвольным N> 1 элементов, кортеж замедляется, ИТЭР не делает:

$ python2.6 -mtimeit -s'x=set(range(99))' 'a=next(iter(x))' 
1000000 loops, best of 3: 0.417 usec per loop 
$ python2.6 -mtimeit -s'x=set(range(99))' 'a=tuple(x)[0]' 
100000 loops, best of 3: 3.12 usec per loop 

Итак, распаковка для случая одноплодной и next(iter(x)) в общем случае, кажется, лучше.

+0

Почему синтаксис Python2.x? Я только там занимаюсь настоящим программированием, а 'python' - это Python 2.5 в моей системе, и, следовательно, что происходит, когда я нажимаю свой keybinding, чтобы открыть консоль python. – u0b34a0f6ae

+0

2.6 отлично подходит для «реального программирования» и богаче 2,5; единственная причина придерживаться 2.5 - если ваша внешняя среда сдерживает вас (App Engine, Civilization 4 и т. д.). next (x) и x.next() работают как в 2.6, но в следующем (x) лучше (вы можете указать значение по умолчанию, а не перехватывать исключения StopIteration, требуется еще один символ ;-). –

+0

@Alex: Не нужно меня убеждать, я бы скорее использовал python 2.6. Я использую debian, debian еще не закончил переход на Python 2.6! (Сам Pyhthon 2.6 доступен, но ни одна из библиотек 3-й части дистрибутива). – u0b34a0f6ae

11

I reckon kaizer.se's answer это здорово. Но если ваш набор может содержать, он содержит более одного элемента, и вам нужен не такой произвольный элемент, вы можете использовать min или max. Например .:

element = min(myset) 

или:

element = max(myset) 

(Не используйте sorted, потому что он имеет излишнюю нагрузку для такого использования.)

2

Я предлагаю:

element = myset.pop() 
+0

Это может работать в некоторых случаях, но оно мутирует набор. – recursive