How to select a random key from a HashMap in Java?

前端 未结 9 1121
小鲜肉
小鲜肉 2021-02-05 05:03

I\'m working with a large ArrayList>, and I would repeatedly need to select a random key from a random HashMap (and do some stuff with it).

相关标签:
9条回答
  • 2021-02-05 06:00

    I managed to find a solution without performance loss. I will post it here since it may help other people -- and potentially answer several open questions on this topic (I'll search for these later).

    What you need is a second custom Set-like data structure to store the keys -- not a list as some suggested here. Lists-like data structures are to expensive to remove items from. The operations needed are adding/removing elements in constant time (to keep it up-to-date with the HashMap) and a procedure to select the random element. The following class MySet does exactly this

    class MySet<A> {
         ArrayList<A> contents = new ArrayList();
         HashMap<A,Integer> indices = new HashMap<A,Integer>();
         Random R = new Random();
    
         //selects random element in constant time
         A randomKey() {
             return contents.get(R.nextInt(contents.size()));
         }
    
         //adds new element in constant time
         void add(A a) {
             indices.put(a,contents.size());
             contents.add(a);
         }
    
         //removes element in constant time
         void remove(A a) {
             int index = indices.get(a);
             contents.set(index,contents.get(contents.size()-1));
             contents.remove(contents.size()-1);
             indices.set(contents.get(contents.size()-1),index);
             indices.remove(a);
         }
    }
    
    0 讨论(0)
  • 2021-02-05 06:06

    Since Java 8, there is an O(log(N)) approach with O(log(N)) additional memory: create a Spliterator via map.entrySet().spliterator(), make log(map.size()) trySplit() calls and choose either the first or the second half randomly. When there are say less than 10 elements left in a Spliterator, dump them into a list and make a random pick.

    0 讨论(0)
  • 2021-02-05 06:06

    How about wrapping HashMap in another implementation of Map? The other map maintains a List, and on put() it does:

    if (inner.put(key, value) == null) listOfKeys.add(key);
    

    (I assume that nulls for values aren't permitted, if they are use containsKey, but that's slower)

    0 讨论(0)
提交回复
热议问题