26

Before 3.6 I would simply use set.pop(). Now, sets are ordered and pop always removes from the start.

What do you think is the most pythonic way?

I'm not sure how I feel about set.remove(random.sample(set, 1)[0]).

  • 1
    The point is that the order (or, for that matter, the previous lack thereof) is an implementation detail you shouldn't rely on. This was never the Pythonic way to do it, as the intention is unclear; if you want a random item, do it explicitly: `set.pop(random.choice(set))` (and note that `set` is a bad name; it shadows the built in). – jonrsharpe Jun 17 '17 at 13:39
  • 1
    @jonrsharpe that was my first try, but it raises `AttributeError`. btw, I agree that it wasn't very pythonic. – Hélio Meira Lins Jun 17 '17 at 13:42
  • 1
    Ah yes, because you can't index a set - I guess that's why [e.g. this](https://stackoverflow.com/a/15837796/3001761) suggests sample. Also you can't pass an argument to `set.pop`. – jonrsharpe Jun 17 '17 at 13:43
  • 2
    "Arbitrary" isn't the same thing as "random" anyway. So it doesn't matter if you're on python 3.6 or not. If you want randomness, the `random` module is the way to go. – Aran-Fey Jun 17 '17 at 13:44
  • There is always `set.discard(random.choice(set))`. – President James K. Polk Jun 17 '17 at 13:46

1 Answers1

22

The set .pop() method does not accept a parameter, it removes an arbitrary (but not random) set value. https://docs.python.org/3.6/library/stdtypes.html#set.pop

Take a set sample with one element random.sample(s, 1) and use set.remove().

>>> s = set([1,2,3,4,5])
>>> el = random.sample(s, 1)[0]
>>> s.remove(el)
>>> print(s)
{1, 3, 4, 5}

The random.choice does not work because sets are not indexed.

>>> random.choice(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/random.py", line 256, in choice
    return seq[i]
iurisilvio
  • 4,727
  • 1
  • 26
  • 31
  • 2
    I think it is cleaner to do `s.remove(random.choice(tuple(s)))` rather than the slightly complicated sample and subscript. Internally `random.sample()` just checks for and converts `set` to `tuple` anyway. – Duncan Apr 17 '20 at 13:09