Split a collection into subcollections of a specific size
18
May 2013
Recently I had to work with a Oracle instance and had to use a query that uses a subquery like (the IN … statement) this
SELECT * FROM table_a WHERE id IN (...)
The method I had to implement/fix takes an arbitrary number of ids as arguments.. if you get
more than 1000 ids, Oracle will spill a message like this into your fa.. aehm.. onto your console:
"ORA-01795 maximum number of expressions in a list is 1000"
To “fix” this problem, I wrote a small utility class that creates sub-collections of a specific maximum size out of a given collection.
Here it is:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class CollectionHelper {
public static <T, U extends Collection<T>> List<U> splitCollectionBySize(final U collection, final int sizePerList) {
if (collection == null)
throw new IllegalArgumentException("given collection may not be null");
if (sizePerList < 1)
throw new IllegalArgumentException("sizePerList must be at least 1");
Iterator<T> iterator = collection.iterator();
List<U> resultList = new ArrayList<U>();
int counter = 0;
try {
U currentCollection = (U) collection.getClass().newInstance();
while (iterator.hasNext()) {
currentCollection.add(iterator.next());
counter++;
if (counter > sizePerList - 1) {
resultList.add(currentCollection);
currentCollection = (U) collection.getClass().newInstance();
counter = 0;
}
}
if (!currentCollection.isEmpty())
resultList.add(currentCollection);
} catch (InstantiationException e) {
throw new IllegalStateException("could not create a instance of the given collection of type " + collection.getClass());
} catch (IllegalAccessException e) {
throw new IllegalStateException("could not create a instance of the given collection of type " + collection.getClass());
}
return resultList;
}
}
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
public class CollectionHelperTest {
@Test(expected = IllegalArgumentException.class)
public void testSplitCollectionBySize_nullArgsForCollection_shouldThrowException() throws Exception {
List<Integer> input = null;
CollectionHelper.splitCollectionBySize(input, 500);
}
@Test(expected = IllegalArgumentException.class)
public void testSplitCollectionBySize_splitSizeSmallerOne_shouldThrowException() throws Exception {
CollectionHelper.splitCollectionBySize(new ArrayList<Object>(), 0);
}
@Test
public void testSplitCollectionBySize_splitBySizeOne() throws Exception {
List<Integer> input = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
input.add(i);
}
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 1);
assertThat(output).isNotNull().isNotEmpty();
assertThat(output.size()).isEqualTo(10);
}
@Test
public void testSplitCollectionBySize_splitByBiggerSizeThanCollectionSize() throws Exception {
List<Integer> input = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
input.add(i);
}
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 500);
assertThat(output).isNotNull().isNotEmpty();
assertThat(output.size()).isEqualTo(1);
assertThat(output.get(0)).isNotNull().isNotEmpty();
assertThat(output.get(0).get(0)).isEqualTo(0);
assertThat(output.get(0).get(99)).isEqualTo(99);
}
@Test
public void testSplitCollectionBySize_splitEmptyCollection() throws Exception {
List<Integer> input = new ArrayList<Integer>();
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 500);
assertThat(output).isNotNull().isEmpty();
assertThat(output.size()).isEqualTo(0);
}
@Test
public void testSplitCollectionBySize_shouldSplit498into10Collections_first9ShouldContain50() throws Exception {
List<Integer> input = new ArrayList<Integer>();
for (int i = 0; i < 499; i++) {
input.add(i);
}
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 50);
assertThat(output).isNotNull().isNotEmpty();
assertThat(output.size()).isEqualTo(10);
for (int i = 0; i < 9; i++) {
assertThat(output.get(i)).isNotNull().isNotEmpty();
assertThat(output.get(i).size()).isEqualTo(50);
}
}
@Test
public void testSplitCollectionBySize_shouldSplit498into10Collections_lastOneShouldBeSmaller() throws Exception {
List<Integer> input = new ArrayList<Integer>();
for (int i = 0; i < 499; i++) {
input.add(i);
}
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 50);
assertThat(output).isNotNull().isNotEmpty();
assertThat(output.size()).isEqualTo(10);
assertThat(output.get(9)).isNotNull().isNotEmpty();
assertThat(output.get(9).size()).isEqualTo(49);
}
@Test
public void testSplitCollectionBySize_shouldSplit500into10Collections() throws Exception {
List<Integer> input = new ArrayList<Integer>();
for (int i = 1; i <= 500; i++) {
input.add(i);
}
List<List<Integer>> output = CollectionHelper.splitCollectionBySize(input, 50);
assertThat(output).isNotNull().isNotEmpty();
assertThat(output.size()).isEqualTo(10);
List<Integer> firstList = output.get(0);
assertThat(firstList).isNotNull().isNotEmpty();
assertThat(firstList.size()).isEqualTo(50);
assertThat(firstList.get(0)).isEqualTo(1);
assertThat(firstList.get(49)).isEqualTo(50);
List<Integer> secondList = output.get(1);
assertThat(secondList).isNotNull().isNotEmpty();
assertThat(secondList.size()).isEqualTo(50);
assertThat(secondList.get(0)).isEqualTo(51);
assertThat(secondList.get(49)).isEqualTo(100);
List<Integer> lastList = output.get(9);
assertThat(lastList).isNotNull().isNotEmpty();
assertThat(lastList.size()).isEqualTo(50);
assertThat(lastList.get(0)).isEqualTo(451);
assertThat(lastList.get(49)).isEqualTo(500);
}
}