Unfortunately, the built-in (bit) set type doesn't have a pop procedure (as does HashSet).
There must be something prettier than
proc pop[T]( S:var set[T] ) : T =
if card(S) == 0 :
raise newException(IndexDefect,"pop on an empty set")
var found : T
for e in S :
found= e
break
S.excl(found)
found
Many thanks for a hint, Helmut
Beauty is subjective, but maybe this?
proc pop[T](s: var set[T]): T =
if card(s) == 0:
raise newException(IndexDefect, "pop on an empty set")
for e in s:
s.excl e
return e
Well, that's because pop is kind of against how bitsets work. There is no insertion order preserved in a set[T], so really there's nothing to pop.
What would you need a pop operation for?
If pop() operation is your priority, then you may use instead a priority queue like
https://nim-lang.org/docs/heapqueue.html
I wonder how iterating over sets works at all -- looking at items() it iterates from low() to high(), but I do not fully trust the comment in
https://nim-lang.org/docs/iterators.html#items.i%2Cset%5BT%5D
iterates only over the elements that are really in the set
From source code it iterates from low to high, and I would guess that both are type properties.
What would you need a pop operation for?
There are two cases:
There are many implementations of sets and no one size fits all. There are tradeoffs in operations supported, space usage and CPU overhead.
For example Nim sets have:
If you have specific requirements.
Write your own tuned to your needs. I've written plenty:
I usually start by writing my requirements, review if Nim sets fits and if not why and the implementation can be derived from those, for example for Monte-Carlo:
# We need a set/hashset with the following properties:
# - Can store up to ~500 elements at most (covered by `set` and `Hashset`)
# - Incl and Excl as fast as possible (in hot path) (covered by `set` and `Hashset`)
# - Can take the length without iterating (in hot path) (covered by `Hashset`, can use a int16 length field or popcount with `set`)
# - Can take a random value from the set as fast as possible (in hot path for Monte-Carlo simulations) (covered by ????)
# - Have access to the last inserted elements for ko checking
# Implementation
# - An array of indices that maps input -> -1 if not present in set or its index in an array of value present (allows incl/excl)
# - An (array of values + length) present in the set (allows fast random pick).
Thanks for all these comments. If I have a set S I can say
for e in S :
echo e
Does Nim construct an iterator of S like items(S) [which doesn't work] ? If yes, how is it called - one could assign via let and call it once to an element of a set.pop could be added to std/setutils (refs https://github.com/nim-lang/Nim/pull/16276),
as i argued here https://github.com/nim-lang/Nim/pull/16276#discussion_r537186214 having a dedicated sets module instead of system allows growing it without bloating the rest.