diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a87900e5a..97ff1465d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,9 @@
+
+ Added "ListUtils#partition" method to split a List into consecutive sublists.
+
Added serialization support for "FixedOrderComparator" and "TransformingComparator".
diff --git a/src/main/java/org/apache/commons/collections/ListUtils.java b/src/main/java/org/apache/commons/collections/ListUtils.java
index 3f492bed2..86736f790 100644
--- a/src/main/java/org/apache/commons/collections/ListUtils.java
+++ b/src/main/java/org/apache/commons/collections/ListUtils.java
@@ -16,6 +16,7 @@
*/
package org.apache.commons.collections;
+import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -438,5 +439,73 @@ public class ListUtils {
}
return -1;
}
+
+ /**
+ * Returns consecutive {@link List#subList(int, int) sublists} of a
+ * list, each of the same size (the final list may be smaller). For example,
+ * partitioning a list containing {@code [a, b, c, d, e]} with a partition
+ * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing
+ * two inner lists of three and two elements, all in the original order.
+ *
+ * The outer list is unmodifiable, but reflects the latest state of the
+ * source list. The inner lists are sublist views of the original list,
+ * produced on demand using {@link List#subList(int, int)}, and are subject
+ * to all the usual caveats about modification as explained in that API.
+ *
+ * Adapted from http://code.google.com/p/guava-libraries/
+ *
+ * @param the element type
+ * @param list the list to return consecutive sublists of
+ * @param size the desired size of each sublist (the last may be smaller)
+ * @return a list of consecutive sublists
+ * @throws IllegalArgumentException if list is {@code null} or size is not strictly positive
+ */
+ public static List> partition(List list, int size) {
+ if (list == null) {
+ throw new IllegalArgumentException("List must not be null");
+ }
+ if (size <= 0) {
+ throw new IllegalArgumentException("Size must be greater than 0");
+ }
+ return new Partition(list, size);
+ }
+ /**
+ * Provides a partition view on a {@link List}.
+ */
+ private static class Partition extends AbstractList> {
+ private final List list;
+ private final int size;
+
+ private Partition(List list, int size) {
+ this.list = list;
+ this.size = size;
+ }
+
+ public List get(int index) {
+ int listSize = size();
+ if (listSize < 0) {
+ throw new IllegalArgumentException("negative size: " + listSize);
+ }
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Index " + index + " must not be negative");
+ }
+ if (index >= listSize) {
+ throw new IndexOutOfBoundsException("Index " + index + " must be less than size " +
+ listSize);
+ }
+ int start = index * size;
+ int end = Math.min(start + size, list.size());
+ return list.subList(start, end);
+ }
+
+ public int size() {
+ return (list.size() + size - 1) / size;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+ }
}
diff --git a/src/test/java/org/apache/commons/collections/TestListUtils.java b/src/test/java/org/apache/commons/collections/TestListUtils.java
index 74e070861..402a13605 100644
--- a/src/test/java/org/apache/commons/collections/TestListUtils.java
+++ b/src/test/java/org/apache/commons/collections/TestListUtils.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import junit.framework.Assert;
import junit.framework.Test;
import org.apache.commons.collections.functors.EqualPredicate;
@@ -30,12 +31,7 @@ import org.apache.commons.collections.list.PredicatedList;
/**
* Tests for ListUtils.
*
- * @version $Revision$
- *
- * @author Stephen Colebourne
- * @author Neil O'Toole
- * @author Matthew Hawthorne
- * @author Dave Meikle
+ * @version $Id$
*/
public class TestListUtils extends BulkTest {
@@ -297,4 +293,32 @@ public class TestListUtils extends BulkTest {
assertEquals(ListUtils.indexOf(fullList, null), -1);
}
+ public void testPartition() {
+ List strings = new ArrayList();
+ for (int i = 0; i <= 6; i++) {
+ strings.add(i);
+ }
+
+ final List> partition = ListUtils.partition(strings, 3);
+
+ assertNotNull(partition);
+ assertEquals(3, partition.size());
+ assertEquals(1, partition.get(2).size());
+
+ try {
+ ListUtils.partition(null, 3);
+ Assert.fail("failed to check for null argument");
+ } catch (IllegalArgumentException e) {}
+
+ try {
+ ListUtils.partition(strings, 0);
+ Assert.fail("failed to check for size argument");
+ } catch (IllegalArgumentException e) {}
+
+ try {
+ ListUtils.partition(strings, -10);
+ Assert.fail("failed to check for size argument");
+ } catch (IllegalArgumentException e) {}
+
+ }
}