I can't seem to find a way to pop a (random) value from a HashSet
. Inspired by other code samples, I wrote the following:
my_set.iter().next().map(|i| my_set.take(i).unwrap())
I.e get an iterator on the set's values, take the first value (a reference) from it, and then run my_set.take()
using the reference previously obtained, to get the value itself (not the reference) and remove it from the set.
This doesn't compile due to:
error[E0500]: closure requires unique access to `my_set` but it is already borrowed
|
32 | my_set.iter().next().map(|i| my_set.take(i).unwrap())
| ------ --- ^^^ ------ second borrow occurs due to use of `my_set` in closure
| | | |
| | | closure construction occurs here
| | first borrow later used by call
| borrow occurs here
I've tried many, many variations on this, but they all fail due to an immutable borrow then being borrowed as mutable (error 502).
Can any one recommend a way to rewrite the above?
If you're okay with cloning the item removed you can do:
let elem = set.iter().next().unwrap().clone();
set.remove(&elem);
Playground
Or with a guard against the set being empty:
if let Some(elem) = set.iter().next().cloned() {
set.remove(&elem);
}
Playground
This feels hacky, but you can use HashSet::retain
with an impure function:
let mut flag = false;
my_set.retain(|_| mem::replace(&mut flag, true));
(playground)
The element removed is truly arbitrary — I ran the code on the playground a few times, and obtained different results.
As interjay mentioned in a comment, this approach iterates over the entire set just to remove one value, so the cost is generally more significant than cloning one value. Therefore, only use this workaround when the element really cannot be cloned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With