Java's Collections.shuffle is doing what?
Yes, you can look at the code; it basically does a Fisher-Yates shuffle. Here it is (thanks OpenJDK, and yay for open source :-P):
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray();
// Shuffle array
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// Dump array back into list
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
The swap method:
private static void swap(Object[] x, int a, int b) {
Object t = x[a];
x[a] = x[b];
x[b] = t;
}
Why does the Collections.shuffle() algorithm work better than my implementation
Collections.Shuffle()
does a Fisher-Yates shuffle. It's a more evenly distributed form of shuffling, and does not reshuffle what might have previously been shuffled already, as opposed to your algorithm.
What your algorithm does (also the known as the naive implementation) is that it will randomly pick any array index and shuffle it over, meaning there's a high chance of it picking the same index that has previously been shuffled already.
The Fisher-Yates shuffle (also known as the Donald Knuth Shuffle) is an unbiased algorithm that shuffles items in the array in an equally likely probability. It avoids the chance if it 'moving' the same objects twice.
Here's a good explanation of the Fisher Yates Shuffle by our own Jeff Atwood at Coding Horror, he discusses the naive implementation of the random shuffle versus the Fisher Yates shuffle.
See also this SO question about Java's implementation. It mentions what you asked. You can also look at the source code if you'd like, as mentioned there. I found it by Googling Collections.shuffle()
in the top 5 links.
To further discuss this, it's always a good idea to use the Fisher-Yates shuffle compared to the naive implementations, especially in implementations that require a higher level of randomness (such as shuffle poker cards) to avoid introducing odds and unfair play. It wouldn't be a good thing if games of chance where implemented based on our naive implementation, as the bias leads to what you've observed, where the same permutation seems to show up more often than the others.
Lastly, as user @jmruc mentioned, here's a very nice tutorial on visualizing algorithms, it contains the Fisher-Yates shuffle, as well as other algorithms, all beautifully presented. Might help you wrap your head around the concepts if you're more of a visualizer: Visualizing Algorithms by Mike Bostock
What does Collections.shuffle function do
I don't think you're really asking about what Collections.shuffle
does in general: I think you're asking why Collections.shuffle
affects the output:
You are creating a load of tasks of two kinds: one of them increments a value ("kind 1"); the other increments a value and sometimes prints a message ("kind 2"). These are put into a list, and executed sequentially.
If you put an equal number of these two kinds of tasks into a list, shuffle them, and execute them sequentially, the item at a position is going to be a "kind 1" task 50% of the time, and a "kind 2" task the rest of the time.
Since "kind 2" tasks only prints for a specific value, you will only get something printed if it is a "kind 2" task at position 2 * size - 1
, which will be 50% of the time.
If you don't shuffle them, but add "kind 1" and "kind 2" in turn, the item at position 2 * size - 1
will always be a "kind 2", so it will always print.
Does Collections.shuffle() randomize list in place?
Yes, the shuffle
method of Collections
indeed shuffles the ArrayList
in place, that also holds for any other Collection
you pass to the method. That is also the case for many other methods there, like sort
.
From the official documentation:
This implementation traverses the list backwards, from the last element up to the second, repeatedly swapping a randomly selected element into the "current position". Elements are randomly selected from the portion of the list that runs from the first element to the current position, inclusive.
And also, very important:
If the specified list does not implement the RandomAccess interface and is large, this implementation dumps the specified list into an array before shuffling it, and dumps the shuffled array back into the list.
This would, for example, be the case for a LinkedList
.
There is also a variant that takes a Random
object, if you want to have more control over the seeding for example, also see the official documentation.
To answer your last question, yes it is a good idea to use that method if you want to have a random permutation of a given collection. The implementation is pretty efficient. However for some special collections you could write a more efficient method, if that is really necessary.
For this I'd recommend to take a look at the implementation of Collections#shuffle
as seen here.
How to shuffle a Collection?
It's not really possible - the Collection abstraction does not define an order, for example a set is Collection, and ordering is not defined on sets, thus shuffling them doesn't make sense.
You should convert your Collection to a list (if it is not a list already) and then shuffle it. See also: How to convert a Collection to List?
How to use Java Collections.shuffle() on a Scala array?
java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))
For the above to work correctly, a's element type has to be a subclass of scala.AnyRef (equivalent to java.lang.Object) because Arrays.asList() uses the array passed in as the backing store for the result java.util.List and java.util.List can contain only object references (not primitive values).*
That is also the reason why Collections.shuffle() which shuffles the passed-in java.util.List actually shuffled the array.*
*: See the note below
For example:
scala> val a = Array[java.lang.Integer](1, 2, 3) // note the type parameter
a: Array[java.lang.Integer] = Array(1, 2, 3)
scala> java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))
scala> a
res43: Array[java.lang.Integer] = Array(1, 3, 2)
scala> java.util.Collections.shuffle(java.util.Arrays.asList(a:_*))
scala> a
res45: Array[java.lang.Integer] = Array(1, 2, 3)
Note: Scala 2.7.5 is used for the above code snippets. Scala 2.8.0 exhibits different behaviors as Daniel demonstrated. To be on the safe side, do not depend on the fact that the array gets shuffled but instead the list that is returned from Arrays.asList() gets shuffled.
scala> val a = Array[java.lang.Integer](1, 2, 3)
a: Array[java.lang.Integer] = Array(1, 2, 3)
scala> val b = java.util.Arrays.asList(a:_*)
b: java.util.List[java.lang.Integer] = [1, 2, 3]
scala> java.util.Collections.shuffle(b)
scala> b
res50: java.util.List[java.lang.Integer] = [2, 1, 3]
scala> java.util.Collections.shuffle(b)
scala> b
res52: java.util.List[java.lang.Integer] = [3, 1, 2]
Related Topics
Rounding Up a Number to Nearest Multiple of 5
Compiler Error: "Class, Interface, or Enum Expected"
Should Methods in a Java Interface Be Declared with or Without a Public Access Modifier
Getting Value of Public Static Final Field/Property of a Class in Java via Reflection
Creating New Generic Object with Wildcard
Java - Read File and Split into Multiple Files
Check If Int Is Between Two Numbers
Why Does Java's Arrays.Sort Method Use Two Different Sorting Algorithms for Different Types
How to Enable the Java Keyword Assert in Eclipse Program-Wise
How to Pass an Integer Class Correctly by Reference
When Does Java's Thread.Sleep Throw Interruptedexception
Custom Objectmapper with Jersey 2.2 and Jackson 2.1
Difference Between Wait and Blocked Thread States
Converting to Upper and Lower Case in Java
Javafx Exception in Thread "Main" Java.Lang.Noclassdeffounderror: Javafx/Application/Application