I have an ArrayList, which I want to divide into smaller Lists of n size, and perform an operation on each. My current method of doing this is
implemented with Array
If you are working with a list 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/
Well i wrote one myself before i saw ColinD's answer (+1) and using Guava is definitely the way to go. It was too much fun to leave alone and so the below gives you a copy of the list rather than views so GUava's is definitely more efficient than this. I'm posting this because it was fun to write rather than suggesting it is as efficient:
The Hamcrest test (one of anyway):
assertThat(chunk(asList("a", "b", "c", "d", "e"), 2),
equalTo(asList(asList("a", "b"), asList("c", "d"), asList("e"))));
The code:
public static <T> Iterable<Iterable<T>> chunk(Iterable<T> in, int size) {
List<Iterable<T>> lists = new ArrayList();
Iterator<T> i = in.iterator();
while (i.hasNext()) {
List<T> list = new ArrayList();
for (int j=0; i.hasNext() && j<size; j++) {
list.add(i.next());
}
lists.add(list);
}
return lists;
}
For example:
int partitionSize = 10;
List<List<String>> partitions = new ArrayList<>();
for (int i=0; i<yourlist.size(); i += partitionSize) {
partitions.add(yourlist.subList(i, Math.min(i + partitionSize, yourlist.size())));
}
for (List<String> list : partitions) {
//Do your stuff on each sub list
}
If you don't want to use a library, here's my solution
1.To partition in N equal parts:
private <T> List<List<T>> nPartition(List<T> objs, final int N) {
return new ArrayList<>(IntStream.range(0, objs.size()).boxed().collect(
Collectors.groupingBy(e->e%N,Collectors.mapping(e->objs.get(e), Collectors.toList())
)).values());
}
2. To partition in sets of N items:
private <T> List<List<T>> nPartition(List<T> objs, final int N) {
return new ArrayList<>(IntStream.range(0, objs.size()).boxed().collect(
Collectors.groupingBy(e->e/N,Collectors.mapping(e->objs.get(e), Collectors.toList())
)).values());
}
In action here: https://ideone.com/QiQnbE
Since you want to optimise your performance you should use a parallel stream instead of a for loop. This way you can use multiple threads.
Lists.partition(A, n).parallelStream().forEach({
//do stuff with temp
});
You can also use other ways to wort with the stream for example collect or map if it matches your purpose.
public <E> Iterable<List<E>> partition(List<E> list, final int batchSize)
{
assert(batchSize > 0);
assert(list != null);
assert(list.size() + batchSize <= Integer.MAX_VALUE); //avoid overflow
int idx = 0;
List<List<E>> result = new ArrayList<List<E>>();
for (idx = 0; idx + batchSize <= list.size(); idx += batchSize) {
result.add(list.subList(idx, idx + batchSize));
}
if (idx < list.size()) {
result.add(list.subList(idx, list.size()));
}
return result;
}