News for hackers. Stuff that matters.
Re:Maps are Broken, for Some Definition of Broken by Strilanc on Tuesday June 22, 2010 @02:28PM (#1452713)
Interesting fact: you can choose a random element from a sequence of unknown size in a single pass. The cost is having to always iterate over the entire sequence, and generating O(n) random numbers instead of O(1).

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).
Re:Maps are Broken, for Some Definition of Broken by sprout on Tuesday June 22, 2010 @01:10PM (#1452447)
HashMap is implemented as a dynamic array, and you could probably get "good enough" random performance from accessing the underlying array, picking a random element, then iterating over that bucket and picking a random element. In the average case this will be pretty much constant time.

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.

Re:Maps are Broken, for Some Definition of Broken by billnapier on Tuesday June 22, 2010 @01:54PM (#1452600)
HashMap (unlike treeset) itself doesn't provide an order guarantee. So can't you just grab the first element from the entrySet and use that?

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.

Re:Maps are Broken, for Some Definition of Broken by apgwoz on Tuesday June 22, 2010 @02:07PM (#1452639)
I of course didn't talk about why I'm using a map, but as an example: consider redis. It's a giant hash table, and it allows you to pick a random key.
Re:Maps are Broken, for Some Definition of Broken by nervechannel on Wednesday June 23, 2010 @03:57AM (#1454388)
Just because it doesn't make any guarantees about order, doesn't mean you'll get a randomly-selected element if you pick the first one.
Re:Maps are Broken, for Some Definition of Broken by gojomo on Tuesday June 22, 2010 @01:59PM (#1452619)
In his hypothetical "using imaginary iterator() on AbstractMap" O(n) solution, he's overlooking that the Set returned by keySet() has an iterator, and doesn't involve any reallocation/copying. So randomKey() can be:

  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)

Re:Maps are Broken, for Some Definition of Broken by apgwoz on Tuesday June 22, 2010 @02:05PM (#1452634)
I did overlook that, so yes, this should work properly. Thanks!

One thing to note is that Random.next() is protected, so it's gotta be random.nextInt(map.size()).

Re:Maps are Broken, for Some Definition of Broken by gojomo on Tuesday June 22, 2010 @03:19PM (#1452858)
Sorry to have referred to you in third-person; wasn't sure you were reading this thread. Thanks for the correction; I've changed my code fragment.
Re:Maps are Broken, for Some Definition of Broken by nervechannel on Tuesday June 22, 2010 @01:54PM (#1452599)
Maps have an entrySet() method that returns a set of key-value Entry objects you can iterate over. Is this what you were after?
Re:Maps are Broken, for Some Definition of Broken by apgwoz on Tuesday June 22, 2010 @02:28PM (#1452714)
keySet() is more appropriate. I just want the key.
Re:Maps are Broken, for Some Definition of Broken by lutorm on Tuesday June 22, 2010 @01:11PM (#1452449)
If you want random elements, why don't just store it in a simple array?
Re:Maps are Broken, for Some Definition of Broken by apgwoz on Tuesday June 22, 2010 @02:29PM (#1452716)
Thanks everyone for the responses. I'm a Java n00b.
Re:Maps are Broken, for Some Definition of Broken by InclinedPlane on Tuesday June 22, 2010 @03:19PM (#1452855)
If you want random access to a map you should write your own implementation. This is a bit like complaining that random access to a linked list is too slow.

Choose appropriate data structures for the task at hand, no one data structure will fit every use.