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
You'll want to do something that makes use of List.subList(int, int) views rather than copying each sublist. To do this really easily, use Guava's Lists.partition(List, int) method:
List<Foo> foos = ...
for (List<Foo> partition : Lists.partition(foos, n)) {
// do something with partition
}
Note that this, like many things, isn't very efficient with a List
that isn't RandomAccess
(such as a LinkedList
).
// Testing data
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
int n = 3;
// One line(statement) with java 8 stream and list.subList
List<List<Integer>> partitions = IntStream.range(0, list.size())
.filter(i -> i % n == 0)
.mapToObj(i -> list.subList(i, Math.min(i + n, list.size() )))
.collect(Collectors.toList());
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SubListTest
{
public static void main(String[] args)
{
List<String> alphabetNames = new ArrayList<String>();
// populate alphabetNames array with AAA,BBB,CCC,.....
int a = (int) 'A';
for (int i = 0; i < 26; i++)
{
char x = (char) (a + i);
char[] array = new char[3];
Arrays.fill(array, x);
alphabetNames.add(new String(array));
}
int[] maxListSizes = new int[]
{
5, 10, 15, 20, 25, 30
};
for (int maxListSize : maxListSizes)
{
System.out.println("######################################################");
System.out.println("Partitioning original list of size " + alphabetNames.size() + " in to sub lists of max size "
+ maxListSize);
ArrayList<List<String>> subListArray = new ArrayList<List<String>>();
if (alphabetNames.size() <= maxListSize)
{
subListArray.add(alphabetNames);
}
else
{
// based on subLists of maxListSize X
int subListArraySize = (alphabetNames.size() + maxListSize - 1) / maxListSize;
for (int i = 0; i < subListArraySize; i++)
{
subListArray.add(alphabetNames.subList(i * maxListSize,
Math.min((i * maxListSize) + maxListSize, alphabetNames.size())));
}
}
System.out.println("Resulting number of partitions " + subListArray.size());
for (List<String> subList : subListArray)
{
System.out.println(subList);
}
}
}
}
Output:
######################################################
Partitioning original list of size 26 in to sub lists of max size 5
Resulting number of partitions 6
[AAA, BBB, CCC, DDD, EEE]
[FFF, GGG, HHH, III, JJJ]
[KKK, LLL, MMM, NNN, OOO]
[PPP, QQQ, RRR, SSS, TTT]
[UUU, VVV, WWW, XXX, YYY]
[ZZZ]
######################################################
Partitioning original list of size 26 in to sub lists of max size 10
Resulting number of partitions 3
[AAA, BBB, CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ]
[KKK, LLL, MMM, NNN, OOO, PPP, QQQ, RRR, SSS, TTT]
[UUU, VVV, WWW, XXX, YYY, ZZZ]
######################################################
Partitioning original list of size 26 in to sub lists of max size 15
Resulting number of partitions 2
[AAA, BBB, CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ, KKK, LLL, MMM, NNN, OOO]
[PPP, QQQ, RRR, SSS, TTT, UUU, VVV, WWW, XXX, YYY, ZZZ]
######################################################
Partitioning original list of size 26 in to sub lists of max size 20
Resulting number of partitions 2
[AAA, BBB, CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ, KKK, LLL, MMM, NNN, OOO, PPP, QQQ, RRR, SSS, TTT]
[UUU, VVV, WWW, XXX, YYY, ZZZ]
######################################################
Partitioning original list of size 26 in to sub lists of max size 25
Resulting number of partitions 2
[AAA, BBB, CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ, KKK, LLL, MMM, NNN, OOO, PPP, QQQ, RRR, SSS, TTT, UUU, VVV, WWW, XXX, YYY]
[ZZZ]
######################################################
Partitioning original list of size 26 in to sub lists of max size 30
Resulting number of partitions 1
[AAA, BBB, CCC, DDD, EEE, FFF, GGG, HHH, III, JJJ, KKK, LLL, MMM, NNN, OOO, PPP, QQQ, RRR, SSS, TTT, UUU, VVV, WWW, XXX, YYY, ZZZ]
One line using Java 8:
IntStream.range(0, list.size() / batchSize + 1)
.mapToObj(i -> list.subList(i * batchSize,
Math.min(i * batchSize + batchSize, list.size())))
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
I just implemented a list partitioning, because I couldn't use a library.
So I want to share my code here:
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class ListPartitioning<T> implements Iterable<List<T>> {
private final List<T> list;
private final int partitionSize;
public ListPartitioning(List<T> list, int partitionSize) {
if (list == null) {
throw new IllegalArgumentException("list must not be null");
}
if (partitionSize < 1) {
throw new IllegalArgumentException("partitionSize must be 1 or greater");
}
this.list = list;
this.partitionSize = partitionSize;
}
@Override
public Iterator<List<T>> iterator() {
return new ListPartitionIterator<T>(list, partitionSize);
}
private static class ListPartitionIterator<T> implements Iterator<List<T>> {
private int index = 0;
private List<T> listToPartition;
private int partitionSize;
private List<T> nextPartition;
public ListPartitionIterator(List<T> listToPartition, int partitionSize) {
this.listToPartition = listToPartition;
this.partitionSize = partitionSize;
}
@Override
public boolean hasNext() {
return index < listToPartition.size();
}
@Override
public List<T> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int partitionStart = index;
int partitionEnd = Math.min(index + partitionSize, listToPartition.size());
nextPartition = listToPartition.subList(partitionStart, partitionEnd);
index = partitionEnd;
return nextPartition;
}
@Override
public void remove() {
if (nextPartition == null) {
throw new IllegalStateException("next must be called first");
}
nextPartition.clear();
index -= partitionSize;
nextPartition = null;
}
}
}
And the unit test based on testng.
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.*;
public class ListPartitioningTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void nullList() {
ListPartitioning<String> lists = new ListPartitioning<String>(null, 1);
}
@Test(groups = Group.UNIT_TEST, expectedExceptions = IllegalArgumentException.class)
public void wrongPartitionSize() {
ListPartitioning<String> lists = new ListPartitioning<String>(new ArrayList<String>(), 0);
}
@Test()
public void iteratorTest() {
List<Integer> integers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7);
Iterator<List<Integer>> partitionIterator = listPartitioning.iterator();
Assert.assertNotNull(partitionIterator);
Assert.assertTrue(partitionIterator.hasNext(), "next partition (first)");
List<Integer> partition = partitionIterator.next();
Assert.assertEquals(partition, Arrays.asList(0, 1, 2, 3, 4, 5, 6));
Assert.assertTrue(partitionIterator.hasNext(), "next partition (second)");
partition = partitionIterator.next();
Assert.assertEquals(partition, Arrays.asList(7, 8, 9, 10, 11, 12, 13));
Assert.assertTrue(partitionIterator.hasNext(), "next partition (third)");
partition = partitionIterator.next();
Assert.assertEquals(partition, Arrays.asList(14, 15));
Assert.assertFalse(partitionIterator.hasNext());
}
@Test(expectedExceptions = NoSuchElementException.class)
public void noSuchElementException() {
List<Integer> integers = Arrays.asList(1);
ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 2);
Iterator<List<Integer>> partitionIterator = listPartitioning.iterator();
List<Integer> partition = partitionIterator.next();
partition = partitionIterator.next();
}
@Test(expectedExceptions = IllegalStateException.class)
public void removeWithoutNext() {
List<Integer> integers = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7);
Iterator<List<Integer>> partitionIterator = listPartitioning.iterator();
partitionIterator.remove();
}
@Test()
public void remove() {
List<Integer> integers = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7);
Iterator<List<Integer>> partitionIterator = listPartitioning.iterator();
partitionIterator.next();
partitionIterator.next();
partitionIterator.remove();
Assert.assertTrue(partitionIterator.hasNext(), "next partition ");
List<Integer> partition = partitionIterator.next();
Assert.assertEquals(partition, Arrays.asList(14, 15));
Assert.assertFalse(partitionIterator.hasNext());
Assert.assertEquals(integers, Arrays.asList(0, 1, 2, 3, 4, 5, 6, 14, 15));
}
}
What about
Arrays.copyOfRange( original, from, to )
?