3

I have a list of 15,000 records. I can maintain the count in a flag.

Integer Counter = 15000;

I want to break my main list into 3 small lists. Each list should contain 5,000 records. First list should contain first 5000 records and second list should contain the next 5,000 records and so on.

The reason behind this: I want to pass each list of 5000 records to a queueable job or create three queueable jobs.

if(mainLst.size() > counter)
{
    List<Custom__C> newList = new List<Custom__C>();
    List<Custom__C> newList1 = new List<Custom__C>();
    List<Custom__C> newList2 = new List<Custom__C>();
    for(Integer i = 0; i< counter; i++)
    {
        newList1.add(mainLst[i]);
    }
    // Perform some operation with newList1    
    // Perform some operation with newList2 
    // Perform some operation with newList3                                   
}  
2
  • What is the purpose of splitting up this list? It will not allow you to circumvent DML-related limits, for example. Or is this some type of exercise?
    – David Reed
    Oct 18, 2018 at 11:44
  • I want to pass these three lists to a queuable/batchapex.
    – Ramy
    Oct 18, 2018 at 19:49

3 Answers 3

10

well, you can use the following my class that I have written with help of community to split List into parts. To read about main logic of splitting you can check How to write a generic list method that will cast at runtime sfdcfox's answer

public with sharing class Lists {

    public static List<List<Object>> doPartions(List<Object> records, Integer size, Type destType){
        checkNotNull(records);
        checkArgument(size > 0);
        checkNotNull(destType);
        return new Partition(records, size, destType).doPartition();
    }

    private static void checkNotNull(Object reference) {
        if (reference == null) {
            throw new NullPointerException();
        }
    }

    private static void checkArgument(Boolean expression) {
        if (!expression) {
            throw new IllegalArgumentException();
        }
    }

    private class Partition{
        private List<Object> items;
        private Integer splitSize;
        private Type destType;

        Partition(List<Object> records, Integer size, Type destType){
            this.items = records;
            this.splitSize = size;
            this.destType = destType;
        }

        List<List<Object>> doPartition(){
            List<List<Object>> result = (List<List<Object>>)destType.newInstance();
            List<Object> protoList = items.clone();
            protoList.clear();
            List<Object> tempList = protoList.clone();
            Integer index = 0, count = 0, size = items.size();
            while(index < size) {
                tempList.add(items.get(index++));
                ++count;
                if(count == splitSize) {
                    result.add(tempList);
                    tempList = protoList.clone();
                    count = 0;
                }
            }
            if(!tempList.isEmpty()) {
                result.add(tempList);
            }
            return result;
        }
    }

    public class IllegalArgumentException extends Exception {}
}

unit-tests

@isTest
private class ListsTest {

    @isTest
    static void testCorrectPartions(){
        List<Integer> records = new List<Integer> {
            1, 2, 3, 4, 5
            };
        Test.startTest();
            List<List<Integer>> actual = (List<List<Integer>>) Lists.doPartions(records, 2, List<List<Integer>>.class);
        Test.stopTest();
        System.assertEquals(3, actual.size(), 'Incorrect number of partions');
        Integer tempNumber = 1;
        for(List<Integer> itemsActual :actual){
            for(Integer numb :itemsActual){
                System.assertEquals(tempNumber, numb, 'Order of elements isn\'t saved');
                ++tempNumber;
            }
        }
    }
}

Usage in your case

List<List<Custom__c>> partionLists = (List<List<Custom__c>>) Lists.doPartions(mainLst, 5000, List<List<Custom__c>>.class);
3
7

You can use switch case to your advantage.

if(mainLst.size() > counter)
{
    List<Custom__C> newList = new List<Custom__C>();
    List<Custom__C> newList1 = new List<Custom__C>();
    List<Custom__C> newList2 = new List<Custom__C>();
    for(Integer i = 0; i< counter; i++)
    {
        Switch on Math.mod(counter,3){
            when 0{
                newList.add(mainLst[i]);
            }
            when 1{
                newList1.add(mainLst[i]);
            }
            when 2{
                newList2.add(mainLst[i]);
            }
        }

    }
    // Perform some operation with newList1    
    // Perform some operation with newList2 
    // Perform some operation with newList3                                   
}  

As david mentioned it will still not allow you to more DML than 10K limit. You have to move it in Batch/Future/Queuebale

2

I came up with this method which will allow you to specify a dynamic partition size and split any list of SObjects to n-lists of the specified size.

  public static List<List<SObject>> split(List<SObject> source, Integer size) {
    List<List<SObject>> ret = new List<List<SObject>>();
    if (source == null) return ret;

    // If the source size is equal to or smaller than our partition size, just return it
    if (source.size() <= size) {
      ret.add(source);
      return ret;
    }

    // Initialize the partitions
    Integer partition = 0;
    ret.add(new List<SObject>());

    for (SObject obj : source) {
      // Create a new partition when we fill one up
      if (ret[partition].size() == size) {
        partition++;
        ret.add(new List<SObject>());
      }
      // Add object to current partition
      ret[partition].add(obj);
    }

    return ret;
  }

Unit test/example usage:

  @IsTest
  public static void splitTest() {
    List<Opportunity> opps = new List<Opportunity>();
    for (Integer i = 0; i < 100; i ++) {
      opps.add(new Opportunity());
    }
    List<List<SObject>> actual = UtilType.split(opps, 5);

    System.assertEquals(20, actual.size());
    System.assertEquals(5, actual[0].size());

  }

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .