Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Saturday, November 22, 2014

Randomized Lists in Java 8

In a quiz-style game, you may need to create a randomized list of questions.  You can always use Collections.shuffle() to rearrange a java.util.List.  However, if you need to separate the iteration from the List, preserving the original order, you can use Java 8 streams.

Randomization makes quiz-style games more effective by presenting questions in an unpredictable order.  If you have a java.util.List of questions, then this will randomize the list.

   Collections.shuffle(listOfQuestions);

However, you may not want to transform the original list.  Or, you want to provide additional filtering in the construction of the randomized list.  You might write a procedure like this.

public List<Integer> randomPermutation(Integer numItems) {

List<Integer> perm = new ArrayList<>();
Integer selectedItems = 0;
Random random = new Random();
while( selectedItems < numItems ) {
Integer i = random.nextInt(numItems);
if( !perm.contains(i) ) {
perm.add( i );
selectedItems++;
}
}
return perm;

}

The function gathers a list of unique integers within the range 0 to numItems.  The while loop may run more than numItems times, depending on whether or not there are collisions.

Java 8 Streams

Using the Random.ints() method instead of the Random.nextInt() method, we can skip the iteration in favor of a function.  The following function re-implements randomPermutation().
  

public List<Integer> randomPermutation2(Integer numItems) {

return new Random().
ints(0, numItems).
distinct().
limit(numItems).
boxed().
collect(Collectors.toList());
}

Let's break this down.

  1. new Random().ints(0, numItems) - Return an unlimited stream of primitive ints between 0 (inclusive) and numItems (exclusive)
  2. distinct() - A stateful check that only unique items are returned
  3. limit(numItems) - Limits the unlimited stream to the number of items we care about
  4. boxed() - Convert int to Integer; alternatively, call "mapToObj(i -> new Integer(i))"
  5. collect(Collectors.toList()) - Turn the stream into a java.utilList for returning


shuffle() is the easiest way to randomize a java.util.List.  But if you need to keep the original ordering of the java.util.List, then Java 8 Streams can provide a way to maintain a separate iteration path.  While the savings between the procedural version of the randomPermutation() algorithm and the Java 8 Streams version isn't significant, it's useful to get used to the new style for when you want to build a pipeline for efficient and scalable data processing.



No comments:

Post a Comment