Explain Codes LogoExplain Codes Logo

Picking a random element from a set

java
random-access
data-structure
collections
Anton ShumikhinbyAnton Shumikhin·Jan 8, 2025
TLDR

Here is a cut-to-the-chase, one-liner way to get a random element from a Set using Stream API:

import java.util.Set; import java.util.concurrent.ThreadLocalRandom; //... Your code somewhere here Set<Integer> set = Set.of(1, 2, 3, 4, 5); // Don't use these numbers for guessing your friend's house lock combo, too predictable. int randomIndex = ThreadLocalRandom.current().nextInt(set.size()); Integer randomElement = set.stream().skip(randomIndex).findFirst().orElse(null); System.out.println(randomElement); // A number more random than your choice of socks this morning.

We use java.util.concurrent.ThreadLocalRandom, which is like the cool uncle of java's Random, to generate a random index. stream.skip() plays "duck, duck, goose" with your set's items to get to the indexed item. Finally, `findFirst() serves you the random element.

Efficient random selection in repetitive scenarios

Sharing is caring: If you are going to be picking random elements frequently like a curious toddler, consider using a shared instance of Random. This avoids the overhead of creating new Random instances and gives you more time to question your life decisions.

Non-Set Collections

For collections that let you directly access elements, such as ArrayList, we can shuffle the whole list with Collections.shuffle and just pick the first one. That’s like shaking a box of candies and picking the one that falls out first. Make sure not to trample any candy-loving toddlers nearby.

Here's an example of the Set-to-List shuffle dance:

import java.util.ArrayList; import java.util.Collections; // ... Set<String> mySet = new HashSet<>(Arrays.asList("Apple", "Banana", "Cherry", "Durian")); List<String> shuffledList = new ArrayList<>(mySet); Collections.shuffle(shuffledList); String randomElement = shuffledList.get(0); System.out.println(randomElement); // I got a... Durian? Blessing or curse?

Custom random-access set: ForwardingSet

Creating a custom set that supports random access, like a supercharged Set, is handy when you need to retrieve and delete elements at lightning speed (O(1)).

Dealing with empty sets

When diving into a set, make sure it isn't a dried-up watering hole. Always check if the collection is empty before trying to do a belly flop in it. This will help you avoid the dreaded NoSuchElementException and bruised egos.

Efficient random iteration

Optimize your loops: One single nextInt call is cheaper than a hipster coffee, and it's all you need to butterfly stroke through your set to your random index.

Considerations when choosing a data structure

One size does not fit all, especially in programming. Choose a data structure that suits your scenario: Need quick insertions, deletions, or access? Or maybe you're running a sophisticated game of bingo and need quick random selections. Choose wisely.

Random selection methods: A platter

There are multiple roads to Rome, and there are multiple ways to pick a random item. Here's a quick rundown:

  1. Shuffling: Good for lists and works in a pinch if you can convert your set to a list. Just don't forget to convert the list back to a set to avoid awkward questions about changing data types at family gatherings.

  2. Programming languages rename their kids for fun: You can achieve the same results in other programming languages as well.

    Remember to check the porter's map, aka the official Java documentation, to avoid getting lost in the strange land of Collections.shuffle.

Trade-offs of each approach

The Stream API is a powerful wizard, but it must feed on your CPU cycles. Remember to carefully choose your approach depending on your application. A clean, readable snippet of code might during runtime turn into a resource-hungry monster.