Picking a random element from a set
int size = myHashSet.size();int item = new Random().nextInt(size); // In real life, the Random object should be rather more shared than thisint i = 0;for(Object obj : myhashSet){ if (i == item) return obj; i++;}
A somewhat related Did You Know:
There are useful methods in java.util.Collections
for shuffling whole collections: Collections.shuffle(List<?>)
and Collections.shuffle(List<?> list, Random rnd)
.
Fast solution for Java using an ArrayList
and a HashMap
: [element -> index].
Motivation: I needed a set of items with RandomAccess
properties, especially to pick a random item from the set (see pollRandom
method). Random navigation in a binary tree is not accurate: trees are not perfectly balanced, which would not lead to a uniform distribution.
public class RandomSet<E> extends AbstractSet<E> { List<E> dta = new ArrayList<E>(); Map<E, Integer> idx = new HashMap<E, Integer>(); public RandomSet() { } public RandomSet(Collection<E> items) { for (E item : items) { idx.put(item, dta.size()); dta.add(item); } } @Override public boolean add(E item) { if (idx.containsKey(item)) { return false; } idx.put(item, dta.size()); dta.add(item); return true; } /** * Override element at position <code>id</code> with last element. * @param id */ public E removeAt(int id) { if (id >= dta.size()) { return null; } E res = dta.get(id); idx.remove(res); E last = dta.remove(dta.size() - 1); // skip filling the hole if last is removed if (id < dta.size()) { idx.put(last, id); dta.set(id, last); } return res; } @Override public boolean remove(Object item) { @SuppressWarnings(value = "element-type-mismatch") Integer id = idx.get(item); if (id == null) { return false; } removeAt(id); return true; } public E get(int i) { return dta.get(i); } public E pollRandom(Random rnd) { if (dta.isEmpty()) { return null; } int id = rnd.nextInt(dta.size()); return removeAt(id); } @Override public int size() { return dta.size(); } @Override public Iterator<E> iterator() { return dta.iterator(); }}