256

How can I split an ArrayList (size=1000) in multiple ArrayLists of the same size (=10) ?

ArrayList<Integer> results;
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
aneuryzm
  • 63,052
  • 100
  • 273
  • 488

22 Answers22

391

You can use subList(int fromIndex, int toIndex) to get a view of a portion of the original list.

From the API:

Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.

Example:

List<Integer> numbers = new ArrayList<Integer>(
    Arrays.asList(5,3,1,2,9,5,0,7)
);

List<Integer> head = numbers.subList(0, 4);
List<Integer> tail = numbers.subList(4, 8);
System.out.println(head); // prints "[5, 3, 1, 2]"
System.out.println(tail); // prints "[9, 5, 0, 7]"

Collections.sort(head);
System.out.println(numbers); // prints "[1, 2, 3, 5, 9, 5, 0, 7]"

tail.add(-1);
System.out.println(numbers); // prints "[1, 2, 3, 5, 9, 5, 0, 7, -1]"

If you need these chopped lists to be NOT a view, then simply create a new List from the subList. Here's an example of putting a few of these things together:

// chops a list into non-view sublists of length L
static <T> List<List<T>> chopped(List<T> list, final int L) {
    List<List<T>> parts = new ArrayList<List<T>>();
    final int N = list.size();
    for (int i = 0; i < N; i += L) {
        parts.add(new ArrayList<T>(
            list.subList(i, Math.min(N, i + L)))
        );
    }
    return parts;
}


List<Integer> numbers = Collections.unmodifiableList(
    Arrays.asList(5,3,1,2,9,5,0,7)
);
List<List<Integer>> parts = chopped(numbers, 3);
System.out.println(parts); // prints "[[5, 3, 1], [2, 9, 5], [0, 7]]"
parts.get(0).add(-1);
System.out.println(parts); // prints "[[5, 3, 1, -1], [2, 9, 5], [0, 7]]"
System.out.println(numbers); // prints "[5, 3, 1, 2, 9, 5, 0, 7]" (unmodified!)
nbro
  • 15,395
  • 32
  • 113
  • 196
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
248

You can add the Guava library to your project and use the Lists.partition method, e.g.

List<Integer> bigList = ...
List<List<Integer>> smallerLists = Lists.partition(bigList, 10);
approxiblue
  • 6,982
  • 16
  • 51
  • 59
Mike Q
  • 22,839
  • 20
  • 87
  • 129
  • 1
    modify the source list, while loop through the sublists, you will get a concurrent exception, because java doc stats : The outer list is unmodifiable, but reflects the latest state of the source list. The inner lists are sublist views of the original list. This is – Junchen Liu Mar 02 '15 at 17:18
91

Apache Commons Collections 4 has a partition method in the ListUtils class. Here’s how it works:

import org.apache.commons.collections4.ListUtils;
...

int targetSize = 100;
List<Integer> largeList = ...
List<List<Integer>> output = ListUtils.partition(largeList, targetSize);
johnnieb
  • 3,982
  • 4
  • 29
  • 32
46

Java 8

We can split a list based on some size or based on a condition.

static Collection<List<Integer>> partitionIntegerListBasedOnSize(List<Integer> inputList, int size) {
        return inputList.stream()
                .collect(Collectors.groupingBy(s -> (s-1)/size))
                .values();
}
static <T> Collection<List<T>> partitionBasedOnSize(List<T> inputList, int size) {
        final AtomicInteger counter = new AtomicInteger(0);
        return inputList.stream()
                    .collect(Collectors.groupingBy(s -> counter.getAndIncrement()/size))
                    .values();
}
static <T> Collection<List<T>> partitionBasedOnCondition(List<T> inputList, Predicate<T> condition) {
        return inputList.stream().collect(Collectors.partitioningBy(s-> (condition.test(s)))).values();
}

Then we can use them as:

final List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
System.out.println(partitionIntegerListBasedOnSize(list, 4));  // [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
System.out.println(partitionBasedOnSize(list, 4));  // [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
System.out.println(partitionBasedOnSize(list, 3));  // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
System.out.println(partitionBasedOnCondition(list, i -> i<6));  // [[6, 7, 8, 9, 10], [1, 2, 3, 4, 5]]
akhil_mittal
  • 23,309
  • 7
  • 96
  • 95
  • @i_am_zero Is it possible to apply multiple conditions (third static method) so you could create multiple lists e.x. [[1,2,3,4], [5,6,7,8,9], [10,11,12,13,14]] on conditions: i<5, 5<=i<10, i>=10 – gooornik07 Nov 19 '19 at 09:26
  • 3
    @gooornik07 a stream can be used only once. – akhil_mittal Nov 19 '19 at 10:06
  • If you replace the list in your example with this list `List.of(10, 20, 30, 40, 50, 60)` then `partitionIntegerListBasedOnSize` won't work! – Muhammad Hewedy Dec 29 '22 at 05:14
39

The answer provided by polygenelubricants splits an array based on given size. I was looking for code that would split an array into a given number of parts. Here is the modification I did to the code:

public static <T>List<List<T>> chopIntoParts( final List<T> ls, final int iParts )
{
    final List<List<T>> lsParts = new ArrayList<List<T>>();
    final int iChunkSize = ls.size() / iParts;
    int iLeftOver = ls.size() % iParts;
    int iTake = iChunkSize;

    for( int i = 0, iT = ls.size(); i < iT; i += iTake )
    {
        if( iLeftOver > 0 )
        {
            iLeftOver--;

            iTake = iChunkSize + 1;
        }
        else
        {
            iTake = iChunkSize;
        }

        lsParts.add( new ArrayList<T>( ls.subList( i, Math.min( iT, i + iTake ) ) ) );
    }

    return lsParts;
}

Hope it helps someone.

29

Java8 streams, one expression, no other libraries:

List<String> input = ...
int partitionSize = ...

 Collection<List<String>> partitionedList = IntStream.range(0, input.size())
    .boxed()
        .collect(Collectors.groupingBy(partition -> (partition / partitionSize), Collectors.mapping(elementIndex -> input.get(elementIndex), Collectors.toList())))
            .values();

Tests:

List<String> input = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h" ,"i");

partitionSize = 1 -> [[a], [b], [c], [d], [e], [f], [g], [h], [I]]

partitionSize = 2 -> [[a, b], [c, d], [e, f], [g, h], [I]]

partitionSize = 3 -> [[a, b, c], [d, e, f], [g, h, I]]

partitionSize = 7 -> [[a, b, c, d, e, f, g], [h, I]]

partitionSize = 100 -> [[a, b, c, d, e, f, g, h, i]]

i000174
  • 1,107
  • 10
  • 15
14

This works for me

/**
* Returns List of the List argument passed to this function with size = chunkSize
* 
* @param largeList input list to be portioned
* @param chunkSize maximum size of each partition
* @param <T> Generic type of the List
* @return A list of Lists which is portioned from the original list 
*/
public static  <T> List<List<T>> chunkList(List<T> list, int chunkSize) {
    if (chunkSize <= 0) {
        throw new IllegalArgumentException("Invalid chunk size: " + chunkSize);
    }
    List<List<T>> chunkList = new ArrayList<>(list.size() / chunkSize);
    for (int i = 0; i < list.size(); i += chunkSize) {
        chunkList.add(list.subList(i, i + chunkSize >= list.size() ? list.size()-1 : i + chunkSize));
    }
    return chunkList;
}

Eg :

List<Integer> stringList = new ArrayList<>();
stringList.add(0);
stringList.add(1);
stringList.add(2);
stringList.add(3);
stringList.add(4);
stringList.add(5);
stringList.add(6);
stringList.add(7);
stringList.add(8);
stringList.add(9);

List<List<Integer>> chunkList = getChunkList1(stringList, 2);
simonalexander2005
  • 4,338
  • 4
  • 48
  • 92
J.R
  • 2,113
  • 19
  • 21
  • 11
    pls note this has a bug that it ignores the last set of data. ex 201 broken into chunks of 100s will return 100,100,0 instead of 100,100,1 – AAP Oct 26 '19 at 14:06
  • Correct code is : chunkList.add(list.subList(i, i + chunkSize >= list.size() ? list.size() : i + chunkSize)); – BluEOS Sep 21 '22 at 17:45
  • Can be a bit shorter: `chunkList.add(list.subList(i, Math.min(i + chunkSize, list.size()));` – Andrey Aug 29 '23 at 17:03
6
private List<List<String>> chunkArrayList(List<String> arrayToChunk, int chunkSize) {
    List<List<String>> chunkList = new ArrayList<>();
    for (int i = 0; i < arrayToChunk.size(); i += chunkSize) {
        int end = Math.min(i + chunkSize, arrayToChunk.size());
        chunkList.add(arrayToChunk.subList(i, end));
    }
    return chunkList;
}

Example

    ArrayList<String> test = new ArrayList<>();
    for (int i=1; i<=1000; i++){
        test.add(String.valueOf(i));
    }

    chunkArrayList(test,10);

Output

CHUNKED:: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30], [31, 32, 33, 34, 35, 36, 37, 38, 39, 40], [41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60], [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], [71, 72, 73, 74, 75, 76, 77, 78, 79, 80], [81, 82, 83, 84, 85, 86, 87, 88, 89, 90], [91, 92, 93, 94, 95, 96, 97, 98, 99, 100], .........

you will see in your log

J.R
  • 2,113
  • 19
  • 21
user3826696
  • 1,045
  • 12
  • 13
4

A similar question was discussed here, Java: split a List into two sub-Lists?

Mainly you can use sublist. More details here : subList

Returns a view of the portion of this list between fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list...

Community
  • 1
  • 1
Incognito
  • 16,567
  • 9
  • 52
  • 74
4

Using the StreamEx library, you can use the StreamEx.ofSubLists(List<T> source, int length) method:

Returns a new StreamEx which consists of non-overlapping sublists of given source list having the specified length (the last sublist may be shorter).

// Assuming you don't actually care that the lists are of type ArrayList
List<List<Integer>> sublists = StreamEx.ofSubLists(result, 10).toList();

// If you actually want them to be of type ArrayList, per your question
List<List<Integer>> sublists = StreamEx.ofSubLists(result, 10).toCollection(ArrayList::new);
M. Justin
  • 14,487
  • 7
  • 91
  • 130
3

I'm guessing that the issue you're having is with naming 100 ArrayLists and populating them. You can create an array of ArrayLists and populate each of those using a loop.

The simplest (read stupidest) way to do this is like this:

ArrayList results = new ArrayList(1000);
    // populate results here
    for (int i = 0; i < 1000; i++) {
        results.add(i);
    }
    ArrayList[] resultGroups = new ArrayList[100];
    // initialize all your small ArrayList groups
    for (int i = 0; i < 100; i++) {
            resultGroups[i] = new ArrayList();
    }
    // put your results into those arrays
    for (int i = 0; i < 1000; i++) {
       resultGroups[i/10].add(results.get(i));
    } 
angstrom91
  • 178
  • 1
  • 8
3

Create a new list and add a sublist view of the source list using the addAll() method to create a new sublist

List<T> newList = new ArrayList<T>();
newList.addAll(sourceList.subList(startIndex, endIndex));
Wolfson
  • 1,187
  • 17
  • 22
user688
  • 31
  • 1
3

You can use the chunk method from Eclipse Collections:

ArrayList<Integer> list = new ArrayList<>(Interval.oneTo(1000));
RichIterable<RichIterable<Integer>> chunks = Iterate.chunk(list, 10);
Verify.assertSize(100, chunks);

A few examples of the chunk method were included in this DZone article as well.

Note: I am a committer for Eclipse Collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
1

You can also use FunctionalJava library - there is partition method for List. This lib has its own collection types, you can convert them to java collections back and forth.

import fj.data.List;

java.util.List<String> javaList = Arrays.asList("a", "b", "c", "d" );

List<String> fList = Java.<String>Collection_List().f(javaList);

List<List<String> partitions = fList.partition(2);
Mikhail Golubtsov
  • 6,285
  • 3
  • 29
  • 36
  • Is this splitting your list into 2 Lists or 2 values per List. For example, if your initial list was 10 elements would this yield 2 lists of 5 or 5 lists of 2. – wheeleruniverse Feb 15 '18 at 21:21
  • @jDub9 this works as it is required in the question. For 10 elements it returns 5 lists of 2. https://github.com/functionaljava/functionaljava/blob/6ac5f9547dbb1f0ca3777be6b366f256e9943194/core/src/main/java/fj/data/List.java#L886 – Mikhail Golubtsov Feb 16 '18 at 06:52
1
import org.apache.commons.collections4.ListUtils;
ArrayList<Integer> mainList = .............;
List<List<Integer>> multipleLists = ListUtils.partition(mainList,100);
int i=1;
for (List<Integer> indexedList : multipleLists){
  System.out.println("Values in List "+i);
  for (Integer value : indexedList)
    System.out.println(value);
i++;
}
0

if you don't want to import the apache commons library try this simple code:

final static int MAX_ELEMENT = 20;

public static void main(final String[] args) {

    final List<String> list = new ArrayList<String>();

    for (int i = 1; i <= 161; i++) {
        list.add(String.valueOf(i));
        System.out.print("," + String.valueOf(i));
    }
    System.out.println("");
    System.out.println("### >>> ");
    final List<List<String>> result = splitList(list, MAX_ELEMENT);

    for (final List<String> entry : result) {
        System.out.println("------------------------");
        for (final String elm : entry) {
            System.out.println(elm);
        }
        System.out.println("------------------------");
    }

}

private static List<List<String>> splitList(final List<String> list, final int maxElement) {

    final List<List<String>> result = new ArrayList<List<String>>();

    final int div = list.size() / maxElement;

    System.out.println(div);

    for (int i = 0; i <= div; i++) {

        final int startIndex = i * maxElement;

        if (startIndex >= list.size()) {
            return result;
        }

        final int endIndex = (i + 1) * maxElement;

        if (endIndex < list.size()) {
            result.add(list.subList(startIndex, endIndex));
        } else {
            result.add(list.subList(startIndex, list.size()));
        }

    }

    return result;
}
B.JAAFAR
  • 13
  • 7
  • @Jaafar:I want the same like but after 20 elements loaded print then again i need to load next 20 elements and so on. So please suggest me for this. – vasantha Apr 21 '17 at 15:03
  • Hi @vasantha sorry i didn't see your request early, you did it or not yet ? – B.JAAFAR May 26 '17 at 13:38
0

Just to be clear, This still have to be tested more...

public class Splitter {

public static <T> List<List<T>> splitList(List<T> listTobeSplit, int size) {
    List<List<T>> sublists= new LinkedList<>();
    if(listTobeSplit.size()>size) {
    int counter=0;
    boolean lastListadded=false;

    List<T> subList=new LinkedList<>();

    for(T t: listTobeSplit) {           
         if (counter==0) {               
             subList =new LinkedList<>();
             subList.add(t);
             counter++;
             lastListadded=false;
         }
         else if(counter>0 && counter<size-1) {
             subList.add(t);
             counter++;
         }
         else {
             lastListadded=true;
             subList.add(t);
             sublists.add(subList);
             counter=0;
         }              
    }
    if(lastListadded==false)
        sublists.add(subList);      
    }
    else {
        sublists.add(listTobeSplit);
    }
    log.debug("sublists: "+sublists);
    return sublists;
 }
}
Vikky
  • 1,123
  • 14
  • 16
0
    **Divide a list to lists of n size**

    import java.util.AbstractList;
    import java.util.ArrayList;
    import java.util.List;

    public final class PartitionUtil<T> extends AbstractList<List<T>> {

        private final List<T> list;
        private final int chunkSize;

        private PartitionUtil(List<T> list, int chunkSize) {
            this.list = new ArrayList<>(list);
            this.chunkSize = chunkSize;
        }

        public static <T> PartitionUtil<T> ofSize(List<T> list, int chunkSize) {
            return new PartitionUtil<>(list, chunkSize);
        }

        @Override
        public List<T> get(int index) {
            int start = index * chunkSize;
            int end = Math.min(start + chunkSize, list.size());

            if (start > end) {
                throw new IndexOutOfBoundsException("Index " + index + " is out of the list range <0," + (size() - 1) + ">");
            }

            return new ArrayList<>(list.subList(start, end));
        }

        @Override
        public int size() {
            return (int) Math.ceil((double) list.size() / (double) chunkSize);
        }
    }





Function call : 
              List<List<String>> containerNumChunks = PartitionUtil.ofSize(list, 999)

more details: https://e.printstacktrace.blog/divide-a-list-to-lists-of-n-size-in-Java-8/

Akhil Sabu
  • 39
  • 5
0

Java8 streams, one expression, no other libraries (two solutions without creating an unnecessary map):

List<List<Integer>> partitionedList = IntStream.range(0, (list.size()-1)/targetSize+1)
        .mapToObj(i -> list.subList(i*targetSize, Math.min(i*targetSize+targetSize, list.size())))
        .collect(Collectors.toList());

List<List<Integer>> partitionedList2 = IntStream.iterate(0, i -> i < list.size(), i -> i + targetSize)
        .mapToObj(i -> list.subList(i, Math.min(i + targetSize, list.size())))
        .collect(Collectors.toList());

Keep in mind these are sublists, so changes to the original list would also affect these.

If you prefer them not to be sublists, and rather newly created independent lists, they can be modified as such:

List<List<Integer>> partitionedList = IntStream.range(0, (list.size()-1)/targetSize+1)
        .mapToObj(i -> IntStream.range(i*targetSize, Math.min(i*targetSize+targetSize, list.size())).mapToObj(j -> list.get(j)).collect(Collectors.toList()))
        .collect(Collectors.toList());

List<List<Integer>> partitionedList2 = IntStream.iterate(0, i -> i < list.size(), i -> i + targetSize)
        .mapToObj(i -> IntStream.range(i, Math.min(i + targetSize, list.size())).mapToObj(j -> list.get(j)).collect(Collectors.toList()))
        .collect(Collectors.toList());
dajavax
  • 3,060
  • 1
  • 14
  • 14
0
List<List<Integer>> allChunkLists = new ArrayList<List<Integer>>();
List<Integer> chunkList = null;
int fromIndex = 0;
int toIndex = CHUNK_SIZE;

while (fromIndex < origList.size()) {
   chunkList = origList.subList(fromIndex, (toIndex > origList.size() ? origList.size() : toIndex));
   allChunkLists.add(chunkList);
   fromIndex = toIndex;
   toIndex += CHUNK_SIZE;
}

No libraries, just Java's subList(). toIndex needs to be bounded properly to avoid out-of-bounds errors in subList().

gene b.
  • 10,512
  • 21
  • 115
  • 227
-1

You need to know the chunk size by which you're dividing your list. Say you have a list of 108 entries and you need a chunk size of 25. Thus you will end up with 5 lists:

  • 4 having 25 entries each;
  • 1 (the fifth) having 8 elements.

Code:

public static void main(String[] args) {

        List<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<108; i++){
            list.add(i);
        }
        int size= list.size();
        int j=0;
                List< List<Integer> > splittedList = new ArrayList<List<Integer>>()  ;
                List<Integer> tempList = new ArrayList<Integer>();
        for(j=0;j<size;j++){
            tempList.add(list.get(j));
        if((j+1)%25==0){
            // chunk of 25 created and clearing tempList
            splittedList.add(tempList);
            tempList = null;
            //intializing it again for new chunk 
            tempList = new ArrayList<Integer>();
        }
        }
        if(size%25!=0){
            //adding the remaining enteries 
            splittedList.add(tempList);
        }
        for (int k=0;k<splittedList.size(); k++){
            //(k+1) because we started from k=0
            System.out.println("Chunk number: "+(k+1)+" has elements = "+splittedList.get(k).size());
        }
    }
iamdanchiv
  • 4,052
  • 4
  • 37
  • 42
-1

Let's suppose you want the considere the class that split the list into multiple chuncks as a library class.

So let's say the class is called 'shared' and in should be final to be sure it won't be extended.

   import java.util.ArrayList;
   import java.util.Arrays;
   import java.util.List;

public final class Shared {
List<Integer> input;
int portion;

public Shared(int portion, Integer... input) {
    this.setPortion(portion);
    this.setInput(input);
}

public List<List<Integer>> listToChunks() {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    int size = this.size();
    int startAt = 0;
    int endAt = this.portion;

    while (endAt <= size) {

        result.add(this.input.subList(startAt, endAt));
        startAt = endAt;
        endAt = (size - endAt < this.portion && size - endAt > 0) ? (this.size()) : (endAt + this.portion);
    }

    return result;
}

public int size() {
    return this.input.size();
}

public void setInput(Integer... input) {
    if (input != null && input.length > 0)
        this.input = Arrays.asList(input);
    else
        System.out.println("Error 001 : please enter a valid array of integers.");
}

public void setPortion(int portion) {
    if (portion > 0)
        this.portion = portion;
    else
        System.out.println("Error 002 : please enter a valid positive number.");
}
}

Next, let's try to execute it from another class that hold the public static void main(String... args)

public class exercise {

public static void main(String[] args) {
    Integer[] numbers = {1, 2, 3, 4, 5, 6, 7};
    int portion = 2;
    Shared share = new Shared(portion, numbers);
    System.out.println(share.listToChunks());   
}
}

Now, if you enter an array of integer [1, 2, 3, 4, 5, 6, 7] with a partition of 2. the result will be [[1, 2], [3, 4], [5, 6], [7]]