diff --git a/projects/samskivert/src/java/com/samskivert/util/CollectionUtil.java b/projects/samskivert/src/java/com/samskivert/util/CollectionUtil.java
index 0c954fd1..cec248fe 100644
--- a/projects/samskivert/src/java/com/samskivert/util/CollectionUtil.java
+++ b/projects/samskivert/src/java/com/samskivert/util/CollectionUtil.java
@@ -1,5 +1,5 @@
//
-// $Id: CollectionUtil.java,v 1.4 2002/03/15 18:05:36 shaper Exp $
+// $Id: CollectionUtil.java,v 1.5 2002/04/11 04:11:23 mdb Exp $
//
// samskivert library - useful routines for java programs
// Copyright (C) 2001 Michael Bayne
@@ -20,9 +20,11 @@
package com.samskivert.util;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
+import java.util.List;
/**
* A collection of collection-related utility functions.
@@ -61,6 +63,59 @@ public class CollectionUtil
}
}
+ /**
+ * Returns a list containing a random selection of elements from the
+ * specified collection. The total number of elements selected will be
+ * equal to count, each element in the source collection
+ * will be selected with equal probability and no element will be
+ * included more than once. The elements in the random subset will
+ * always be included in the order they are returned from the source
+ * collection's iterator.
+ *
+ *
Algorithm courtesy of William R. Mahoney, published in
+ * Dr. Dobbs Journal, February 2002.
+ *
+ * @exception IllegalArgumentException thrown if the size of the
+ * collection is smaller than the number of elements requested for the
+ * random subset.
+ */
+ public static List selectRandomSubset (Collection col, int count)
+ {
+ int csize = col.size();
+ if (csize < count) {
+ String errmsg = "Cannot select " + count + " elements " +
+ "from a collection of only " + csize + " elements.";
+ throw new IllegalArgumentException(errmsg);
+ }
+
+ ArrayList subset = new ArrayList();
+ Iterator iter = col.iterator();
+ int s = 0;
+
+ for (int k = 0; iter.hasNext(); k++) {
+ Object elem = iter.next();
+
+ // the probability that an element is select for inclusion in
+ // our random subset is proportional to the number of elements
+ // remaining to be checked for inclusion divided by the number
+ // of elements remaining to be included
+ float limit = ((float)(count - s)) / ((float)(csize - k));
+
+ // include the record if our random value is below the limit
+ if (Math.random() < limit) {
+ subset.add(elem);
+
+ // stop looking if we've reached our target size
+ if (++s == count) {
+ break;
+ }
+ }
+ }
+
+ return subset;
+ }
+
+
/**
* If a collection contains only Integer objects, it can
* be passed to this function and converted into an int array.
diff --git a/projects/samskivert/tests/src/java/com/samskivert/util/CollectionUtilTest.java b/projects/samskivert/tests/src/java/com/samskivert/util/CollectionUtilTest.java
new file mode 100644
index 00000000..d7fcd40b
--- /dev/null
+++ b/projects/samskivert/tests/src/java/com/samskivert/util/CollectionUtilTest.java
@@ -0,0 +1,46 @@
+//
+// $Id: CollectionUtilTest.java,v 1.1 2002/04/11 04:11:23 mdb Exp $
+
+package com.samskivert.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Tests the {@link CollectionUtil} class.
+ */
+public class CollectionUtilTest extends TestCase
+{
+ public CollectionUtilTest ()
+ {
+ super(CollectionUtil.class.getName());
+ }
+
+ public void runTest ()
+ {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < 100; i++) {
+ list.add(new Integer(i));
+ }
+
+ for (int i = 0; i < 10; i++) {
+ List subset = CollectionUtil.selectRandomSubset(list, 10);
+ // System.out.println(StringUtil.toString(subset));
+ assertTrue("length == 10", subset.size() == 10);
+ }
+ }
+
+ public static Test suite ()
+ {
+ return new CollectionUtilTest();
+ }
+
+ public static void main (String[] args)
+ {
+ CollectionUtilTest test = new CollectionUtilTest();
+ test.runTest();
+ }
+}