What\'s the simplest, most standard, and/or most efficient way to split a List into two sub-Lists in Java? It\'s OK to mutate the original List, so no copying should be nece
import java.util.Collection;
public class CollectionUtils {
/**
* Will split the passed collection so that the size of the new collections
* is not greater than maxSize
* @param t
* @param maxSize
* @return a List containing splitted collections
*/
@SuppressWarnings("unchecked")
public static <T> List<Collection<T>>split(Collection<T> t, int maxSize) {
int counter = 0;
List<Collection<T>> ret = new LinkedList<Collection<T>>();
Iterator<T>itr = t.iterator();
try {
Collection<T> tmp = t.getClass().newInstance();
ret.add(tmp);
while(itr.hasNext()) {
tmp.add(itr.next());
counter++;
if(counter>=maxSize && itr.hasNext()) {
tmp = t.getClass().newInstance();
ret.add(tmp);
counter=0;
}
}
} catch(Throwable e) {
Logger.getLogger(CollectionUtils.class).error("There was an error spliting "+t.getClass(),e);
}
return ret;
}
}
// JUnit test cases
import java.util.ArrayList;
/**
*
* $Change$
* @version $Revision$
* Last modified date & time $DateTime$
*/
public class CollectionUtilsTest {
@Test
public void testSplitList() {
List<Integer>test = new ArrayList<Integer>(100);
for (int i=1;i<101;i++) {
test.add(i);
}
List<Collection<Integer>> tests = CollectionUtils.split(test, 10);
Assert.assertEquals("Size mismatch", 10,tests.size());
TreeSet<Integer> tmp = new TreeSet<Integer>();
for(Collection<Integer> cs:tests) {
for(Integer i:cs) {
Assert.assertFalse("Duplicated item found "+i,tmp.contains(i));
tmp.add(i);
}
System.out.println(cs);
}
int why = 1;
for(Integer i:tmp) {
Assert.assertEquals("Not all items are in the collection ",why,i.intValue());
why++;
}
}
@Test
public void testSplitSet() {
TreeSet<Integer>test = new TreeSet<Integer>();
for (int i=1;i<112;i++) {
test.add(i);
}
List<Collection<Integer>> tests = CollectionUtils.split(test, 10);
Assert.assertEquals("Size mismatch", 12,tests.size());
TreeSet<Integer> tmp = new TreeSet<Integer>();
int cI = 0;
for(Collection<Integer> cs:tests) {
for(Integer i:cs) {
Assert.assertFalse("Duplicated item found "+i,tmp.contains(i));
tmp.add(i);
}
// if(cI>10) {
System.out.println(cs);
// }
cI++;
}
int why = 1;
for(Integer i:tmp) {
Assert.assertEquals("Not all items are in the collection ",why,i.intValue());
why++;
}
}
}
Riffing on Marc's solution, this solution uses a for
loop that saves some calls to list.size()
:
<T> List<T> split(List<T> list, int i) {
List<T> x = new ArrayList<T>(list.subList(i, list.size()));
// Remove items from end of original list
for (int j=list.size()-1; j>i; --j)
list.remove(j);
return x;
}
I use the "Apache Commons Collections 4" library. It has a partition method in the ListUtils class:
...
int targetSize = 100;
List<Integer> largeList = ...
List<List<Integer>> output = ListUtils.partition(largeList, targetSize);
This method is adapted from http://code.google.com/p/guava-libraries/
//Here is my list
ArrayList<T> items=new ArrayList<T>();
Integer startIndex = 0;
int j = 0;
for (; j < items.size() - 1; j++) {//always start with next index not again 0
for (int i = 0; i < 4; i++) { // divide into equal part with 4 item
startIndex = startIndex + 1;
j = startIndex;
}
}
Getting the returned array is pretty easy using the subList method, but there's no easy way that I know of to remove a range of items from a List.
Here's what I have:
<T> List<T> split(List<T> list, int i) {
List<T> x = new ArrayList<T>(list.subList(i, list.size()));
// Remove items from end of original list
while (list.size() > i) {
list.remove(list.size() - 1);
}
return x;
}
<T> List<T> split(List<T> list, int i) {
List<T> secondPart = list.sublist(i, list.size());
List<T> returnValue = new ArrayList<T>(secondPart());
secondPart.clear(),
return returnValue;
}