Maps are Broken, for Some Definition of Broken
sigusr2.net
sigusr2.net
The algorithm is quite simple:
var choice = elements.First()
var n = 1
for e in elements.Skip(1):
n += 1
if rand(n) == 0:
choice = e
The algorithm is correct because, at each stage, each of the preceding elements is chosen with probability 1/n. The invariant is maintained because the next element is chosen with probability 1/(n+1) and therefore scales the preceding probabilities by n/(n+1) giving 1/(n+1).I'd be a little worried about the randomness of the distribution, but if you need a proper random distribution, you shouldn't be using a map.
But I think the bigger problem is trying to use a Map in the first place when maybe a different data structure will solve the problem better.
int index = random.nextInt(map.size());
for(String key : map.keySet()) {
if(index==0) return key;
index--;
}
Abstractly, maps aren't the right structure for quick/constant-time random-choice. He could possibly choose an internal implementation that was better at offering random-choice, but that's unlikely to be the optimal implementation for other map uses. He could maintain a parallel structure during inserts that allows constant-draws later. Or do one array shuffle after all inserts, before all draws (if that fits the usage pattern).(edit: code corrected per replies below)
One thing to note is that Random.next() is protected, so it's gotta be random.nextInt(map.size()).
Choose appropriate data structures for the task at hand, no one data structure will fit every use.