264

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

ArrayList<Integer> results;
2

24 Answers 24

397

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!)
Sign up to request clarification or add additional context in comments.

Comments

253

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);

1 Comment

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
97

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);

Comments

47

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]]

3 Comments

@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 a stream can be used only once.
If you replace the list in your example with this list List.of(10, 20, 30, 40, 50, 60) then partitionIntegerListBasedOnSize won't work!
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.

Comments

38

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]]

6 Comments

This answer is underrated. The most clean way to do it at the end of 2021
How can I use this for android ?
It's a neat trick, but it's hard to see what's going on. I wouldn't use it.
@Zyl Hide it in a aptly-named method, sprinkle some unit tests to better document it.
What is memory consumption and computing complexity of this solution?
|
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);

3 Comments

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
Correct code is : chunkList.add(list.subList(i, i + chunkSize >= list.size() ? list.size() : i + chunkSize));
Can be a bit shorter: chunkList.add(list.subList(i, Math.min(i + chunkSize, list.size()));
8
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

Comments

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...

Comments

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);

Comments

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));
    } 

Comments

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.

Comments

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));

Comments

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);

2 Comments

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.
@jDub9 this works as it is required in the question. For 10 elements it returns 5 lists of 2. github.com/functionaljava/functionaljava/blob/…
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++;
}

Comments

1

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());

1 Comment

Excellent solution. Simple, easy to undestand and all with native Java.
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;
}

2 Comments

@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.
Hi @vasantha sorry i didn't see your request early, you did it or not yet ?
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;
 }
}

Comments

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/

Comments

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().

Comments

0

Whilst exercising on java oop exam I bumped into a similar issue, and for God sake, I implemented it in such easy way just relying on java streams.

Below method basically breaks input list into a subsequence of desired size and maps each enumerator representative into a sublist with limited size. The skip method is used to skip previous computations and by stream one-use nature it's mandatory.

Here what I implemented:

public <X> List<List<X>> split(final List<X> list, final int dividend) {
      return IntStream.range(
              0, 
              list.size() / dividend
          )
          .mapToObj(
              y -> list.stream()
                  .skip(dividend * y)
                  .limit(dividend)
                  .collect(Collectors.toList())
          )
          .collect(Collectors.toList());
}

Comments

0

The Gatherers.windowFixed gatherer in Java 24 (available as a preview language feature since Java 22) partitions a stream into groups of a given size. This can be used to achieve your goal of partitioning a List into a list of fixed-sized sublists.

List<Integer> listOfSize1000 = createList();

List<List<Integer>> listsOfSize10 =
        listOfSize1000.stream().gather(Gatherers.windowFixed(10)).toList();

This uses the new Stream.gather method with the new windowFixed gatherer to convert the list's stream Stream<Integer> to a Stream<List<Integer>>. This is then collected into a List using Stream.toList(). This new feature was added to the language with the JEP 485: Stream Gatherers feature.

Your actual question requests ArrayList values. If for some reason you care that the values are ArrayLists and not the immutable lists created above, you can map and collect the values as needed:

ArrayList<ArrayList<Integer>> arrayListsOfSize10 = listOfSize1000.stream()
        .gather(Gatherers.windowFixed(10))
        .map(ArrayList::new)
        .collect(Collectors.toCollection(ArrayList::new));

Javadocs

Gatherer:

An intermediate operation that transforms a stream of input elements into a stream of output elements, optionally applying a final action when the end of the upstream is reached. […]

[…]

There are many examples of gathering operations, including but not limited to: grouping elements into batches (windowing functions); de-duplicating consecutively similar elements; incremental accumulation functions (prefix scan); incremental reordering functions, etc. The class Gatherers provides implementations of common gathering operations.

Stream.gather:

Returns a stream consisting of the results of applying the given gatherer to the elements of this stream.

Gatherers.windowFixed

Returns a Gatherer that gathers elements into windows -- encounter-ordered groups of elements -- of a fixed size. If the stream is empty then no window will be produced. The last window may contain fewer elements than the supplied window size.

Example:

// will contain: [[1, 2, 3], [4, 5, 6], [7, 8]]
List<List<Integer>> windows =
    Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowFixed(3)).toList();

Comments

-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());
        }
    }

Comments

-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]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.