29

I would like to get an element from a frozenset (without modifying it, of course, as frozensets are immutable). The best solution I have found so far is:

s = frozenset(['a'])
iter(s).next()

which returns, as expected:

'a'

In other words, is there any way of 'popping' an element from a frozenset without actually popping it?

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
ablondin
  • 427
  • 1
  • 4
  • 7
  • 4
    I think your method is as good as any. If you want a random element you might check out `random.sample(fset, 1)`. – bbayles Jul 23 '13 at 04:52
  • Why do you want to pop the element, because it's arbitrary? – martineau Jul 23 '13 at 05:16
  • 1
    I just want to get some arbitrary element from a frozenset. I shouldn't have used the word pop since the set remains unchanged. It is similar to peeking the first element of a stack without popping it. – ablondin Jul 23 '13 at 05:32
  • 1
    That's what I use (but with the `next` builtin instead of the method). – user2357112 Jul 23 '13 at 05:58
  • 1
    Don't use the method `.next()`. There is a `next()` built-in function since at least python2.6 and using it means that your code will work also in python3 where the `next` method was renamed `__next__`. – Bakuriu Jul 23 '13 at 09:32
  • @user2357112 and @Bakuriu: Thank you for your answers, especially Bakuriu for the explanation of the difference between `next(iter(fset))` and `iter(fset).next()`. – ablondin Jul 23 '13 at 17:52
  • @Bo102010 `random.sample(fset, 1)` returns a list; you need `random.sample(fset, 1)[0]` to get the element itself. – Zero Piraeus Jul 24 '13 at 20:21

4 Answers4

23

If you know that there is but one element in the frozenset, you can use iterable unpacking:

s = frozenset(['a'])
x, = s

This is somewhat a special case of the original question, but it comes in handy some times.

If you have a lot of these to do it might be faster than next(iter..:

>>> timeit.timeit('a,b = foo', setup='foo = frozenset(range(2))', number=100000000)
5.054765939712524
>>> timeit.timeit('a = next(iter(foo))', setup='foo = frozenset(range(2))', number=100000000)
11.258678197860718
John Mee
  • 50,179
  • 34
  • 152
  • 186
Dominic Kempf
  • 241
  • 2
  • 7
20

(Summarizing the answers given in the comments)

Your method is as good as any, with the caveat that, from Python 2.6, you should be using next(iter(s)) rather than iter(s).next().

If you want a random element rather than an arbitrary one, use the following:

import random
random.sample(s, 1)[0]

Here are a couple of examples demonstrating the difference between those two:

>>> s = frozenset("kapow")
>>> [next(iter(s)) for _ in range(10)]
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
>>> import random
>>> [random.sample(s, 1)[0] for _ in range(10)]
['w', 'a', 'o', 'o', 'w', 'o', 'k', 'k', 'p', 'k']
Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
12

You could use with python 3:

>>> s = frozenset(['a', 'b', 'c', 'd'])
>>> x, *_ = s
>>> x
'a'
>>> _, x, *_ = s
>>> x
'b'
>>> *_, x, _ = s
>>> x
'c'
>>> *_, x = s
>>> x
'd'
tammoj
  • 908
  • 10
  • 14
1

Using list:

list_ = list(frozenset("Benyamin"))

Using generator:

def get_frozenset_elements(frozen_set):
    for i in frozen_set:
        yield i

gen_ = get_frozenset_elements(frozenset("Benyamin"))
next(gen_)
next(gen_)
next(gen_)
...

Using iterator:

iter_ = iter(frozenset("Benyamin"))
next(gen_)
next(gen_)
next(gen_)
...

[NOTE]:

Difference between Python's Generators and Iterators

Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150
  • 1
    The first of these is just a complicated way to write `list(my_frozenset)`, which is quite wasteful for large sets. The second is just a complicated way to write `next(iter(my_frozenset))`, which is already the accepted answer. – wchargin Jan 06 '20 at 18:15