From 6caf731ff9382f62816d6f341d48858e3ef8625e Mon Sep 17 00:00:00 2001 From: "samskivert@gmail.com" Date: Thu, 11 Apr 2002 04:11:23 +0000 Subject: [PATCH] Added selectRandomSubset() which selects a random subset of elements (with equal probability) from a collection. git-svn-id: https://samskivert.googlecode.com/svn/trunk@701 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../com/samskivert/util/CollectionUtil.java | 57 ++++++++++++++++++- .../samskivert/util/CollectionUtilTest.java | 46 +++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 projects/samskivert/tests/src/java/com/samskivert/util/CollectionUtilTest.java 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(); + } +}