简体   繁体   中英

Randomly choose an element of a hashset using java

I have a function where I have to randomly choose an element from a HashSet and then test if this element meets a condition. If the condition is true then return the chosen element otherwise we must randomly choose another element.

I tried the followin code:

private  Number[] findClosest( int remCapacity, HashSet<Integer> remainingNodes, VrpProblem problem) {
    int[] demands = problem.getDemands();
    int bestNodeId = -1;
    Iterator<Integer> iter =  remainingNodes.iterator();
            
    Random random = new Random();
               
    while (iter.hasNext()) {
        int nodeId = random.nextInt(remainingNodes.size());
                  
        if (demands[nodeId] > remCapacity) {
            continue;
        }    
        bestNodeId = nodeId;              
     }     
     return new Number[] {new Integer(bestNodeId)}  ;  
}

But it didn't work.

You are currently not reading any value from the remainingNodes set. Depending on how expensive your solution can be, you can use the following approach:

  1. Load all the Set<Integer> values in a List<Integer> instance.
  2. Shuffle the list.
  3. Iterate over the list and do your check.

So the source code can look like this:

List<Integer> list = new ArrayList<Integer>(remainingNodes);
Collections.shuffle(list);
for (Integer value : list) {
    if (yourCheckTestHereWith_value_andOtherVariables) {
        return value;
    }
}

Keep in mind that there might be a case where no value in the Set fits your condition. You have to define a fallback case after the for loop to handle that situation (throw exception, return null , etc.).

One solution is to provide a method that returns a randomIterator to iterate over the set contents. This works like a regular iterator except the elements are returned in a random order with no repeats. It works as follows:

  • The method first puts the set in a list. This is necessary so that individual elements may be retrieved.
  • using an algorithm similar to Fischer-Yates start shuffling the list. The shuffle algorithm proceeds, one element at a time, as next() is called. The iterator works in O(n) time where n is the number of elements in the set.
Set<Integer> remainingNodes = 
Iterator<Integer> iter = randomIterator(remainingNodes);
    
while (iter.hasNext()) {
    int item = iter.next();
    // do the test
}

Method to return the iterator.

public static <T> Iterator<T>
        randomIterator(Collection<T> collection) {
    
    return new Iterator<T>() {
        List<T> copy = new ArrayList<>(collection);
        int nItems = copy.size();
        
        public boolean hasNext() {
            return nItems != 0;
        }
        
        public T next() {
            int k = (int) (Math.random() * nItems);
            T returnVal = copy.get(k);
            copy.set(k, copy.get(--nItems));
            return returnVal;
        }
    };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM