Best way to remove element from list or why they kept iterator without this option

  • I'm studing apex now and dont understand the situation with list and iterator. In java you cant delete in any way elements from list while iterating it. So therefore developers added iterator and also added removeAll method to list. Here are some examples.

    Deleting element by using another list in java:

        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
    
        List<Integer> listToRemove = new ArrayList<Integer>();
    
        for (Integer num : list) {
            if (num==1){
                listToRemove.add(num);
            }
        }
    
        list.removeAll(listToRemove);
        System.out.println(list);
    

    Result: [2, 3]

    Deleting element by using iterator in java:

        Iterator<Integer> iterator = list.iterator();
    
        while(iterator.hasNext()){
            if(iterator.next() == 1){
                iterator.remove();
            }
        }
        System.out.println(list);
    

    Result: [2, 3]

    Ok, then i decided to do the same on apex.

    Firstly, i didn't find removeAll method for list. Bad luck :)

    Then i found iterator and thought that logic is the same as in java, but got this:

    Method does not exist or incorrect signature: [Iterator].remove()

    Almost the same, they kept hasNext(), next(), but they did not keep a remove() method. Why? :)

    Then i tried to do something like this:

    Iterator<Integer> iter = li.iterator();   Integer count = 0;
    
    while(iter.hasNext()){
        Integer temp = iter.next();    
        if(temp == 1){
            li.remove(count);
        }
        count++;   
    }   
    System.debug(li);
    

    It doesn't work also.

    So the only way that works for me is:

        for (Integer i = 0; i < li.size(); i++) {
            if (li.get(i) == 1){
                li.remove(i);
                i--;
            }
        }
    

    Can you please share with me with the best way of removing elements form list!? Thanks in advance!

    Internally the `List` in Apex is a Java `ArrayList` type which is a resizable array. When you remove an item from the array, the entire collection shifts left (one position removed from the element indices).

    Do you have a reference for this?

  • The idiomatic way to do this in other languages without iterator semantics is to iterate through the list backwards.

    For example:

    public static List<Object> removeAll(List<Object> target, Object toRemove) {
        for(Integer i = target.size() - 1; i >= 0; i--) {
            if(target[i].equals(toRemove)) {
                target.remove(i);
            }
        }
    
        return target;
    }
    

    question: if `target`'s objects and `toRemove` are custom types, do they have to implement an `equals()` and `hashcode()` method?

    @cropredy Yes and no. Ideally yes though. If you don't implement them it will only remove things if they are the same object in memory.

  • I don't know if it's a best practice, but one way to reverse your approach and make a second list of the items you want to keep, then once you're done iterating, reassign that to your primary list.

    So, using your code, it would be:

        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
    
        List<Integer> listToKeep = new ArrayList<Integer>();
    
        for (Integer num : list) {
            if (num != 1){
                listToKeep.add(num);
            }
        }
    
        list = listToKeep;
        System.out.println(list);
    

    this one is only good if we don't have a huge list, because then we will do add operation many times, but thanks anyway. So there is no "special" apex method or style for manipulation with list?!

  • If the List doesn't have to have duplicates, you can convert to Set and use remove method on the Set.

    List<Integer> listOfInts = new List<Integer>();
    Set<Integer> setOfInts = new Set<Integer>(listOfInts);
    
    for(Integer i : setOfInts) {
        if(i == 1) {
            setOfInts.remove(i);
        }
    }
    

    Your code will actually error when you try to remove things from a set you are iterating through and won't work.

    No, it will succeed.

    it doesnt work, because we cant use variable names like: list, set.. Because code in apex is case insensitive

    Yes, as for name you are right (it's just an example), but the logic is fine and works correctly.

    Have you tried that logic? You cannot remove something from a collection as you are iterating through it.

    I have tried it - works ok, have you tried?

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM

Tags used