jun
jun

Reputation: 61

Understanding this removeAll java method with arrayList

This method's duty is to remove all occurrences of the value toRemove from the arrayList. The remaining elements should just be shifted toward the beginning of the list (the size will not change). All "extra" elements at the end (however many occurrences of toRemove were in the list) should just be filled with 0. The method has no return value, and if the list has no elements it should just have no effect. Cannot use remove() and removeAll() from the ArrayList class.

The method signature is:

public static void removeAll(ArrayList<Integer> list, int toRemove);

The solution:

public static void removeAll(ArrayList<Integer> list, int toRemove) {
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i) = toRemove) {
            for (int j = i + 1; j < list.size(); j++) {
                list.set(j - 1, list.get(j));
            }
            list.set(list.size() - 1, 0);
            i--;
        }
    }

I understand the first for loop and the if statement well. Because one would want to iterate through the entire arrayList one-by-one and for each index with a number present in the arrayList check if it is, in fact the toRemovee integer. After this point I become lost.

Why another for loop? Why do we start the second for-loop one after where the last one was? Why within that second for loop do we use list.set(), I understand that set method takes in two arguments, the index position and the element to sub into that designated position. Why j-1? Why after this second loop is over is there the line: list.set(list.size()-1, 0) ? Why the i--?

There are a lot of moving parts and I would like to understand the logic.

Thank you

Upvotes: 2

Views: 996

Answers (3)

WillD
WillD

Reputation: 875

If you want to do the same in an FP style; return a new List instead of modifying the input, you can do this with Streams.

public static List<Integer> removeAll(ArrayList<Integer> list, int toRemove) {
    Integer rem = new Integer(toRemove); // OR change toRemove to Integer
    List<Integer> ret =  list.stream()
                   .filter(i -> !(i.equals(rem)))
                   .collect(Collectors.toList());
    return ret;
    //if you NEED to return ArrayList instead of List
    //return new ArrayList<>(ret);
}

Upvotes: 0

Arnaud
Arnaud

Reputation: 17534

Why do we start the second for-loop one after where the last one was?

Each time an occurence is found, we want to left shift by 1 all following values of the arraylist.

Why within that second for loop do we use list.set(), I understand that set method takes in two arguments, the index position, and the element to sub into that designated position. Why j - 1?

j-1 is used to shift left by 1 .

Why after this second loop is over is there the line: list.set(list. sise () - 1, 0) ?

We shifted values left, but the value at the last index (size-1) has not been replaced by anything, we want it to be 0 .

why the i--?

As the value at the current index has been overwritten by another value, we want to start next iteration at the same index (i-- compensating i++).

Upvotes: 0

Salem
Salem

Reputation: 14917

Why another for-loop? Why do we start the second for-loop one after where the last one was? Why within that second for loop do we use list.set(), I understand that set method takes in two arguments, the index position, and the element to sub into that designated position. Why j - 1?

The method does everything the documentation says. The inner loop shifts the elements left by one.

for (int j = i + 1; j < list.size(); j++) {
    list.set(j - 1,       //The index before j (that is, j - 1) is set to...
            list.get(j)); //the current element.
    }
}

Starting at the element after the found index, it sets the one to the left to the current element. Eventually, you'll end up with all elements having been shifted left.

list.set(list.size() - 1, 0);

This sets the last element to zero. Since your list has had one element removed, you need to get rid of the last one because everything has been shifted.

Example:

In these examples, ^ is i and * is j.

0 1 2 3 4

Say I want to remove 2.
First, I'll loop until I find 2.

0 1 2 3 4
    ^ index: 2

Now, I'll shift everything left to remove that element. Because we're shifting left, we need to start at i + 1 (hence the for-loop starting at i + 1.

0 1 3 3 4
    ^ * (replaced the one before *)

Next, we do it again.

0 1 3 4 4
    ^   *

Now we're done.

list.set(list.size() - 1, 0);

However, 4 is left at the end. We need to remove that because we removed an element, and the list is one element shorter. So, we set the last element to zero to remove it (of course, this assumes zero is not a valid value in the list).

Note:

I would strongly suggest doing list.remove(list.size() - 1) instead of the call to set. This actually removes the last item and does not leave it with a "magic number" default value.

Why the i--?

You need i-- because everything has been shifted left, so you'll need to update the index 1 to the left, namely by subtracting one. (Actually, what you need to do is start the iteration at the same index, but since the for-loop executes i++ every iteration you need to do i-- to "cancel" it out.)

Upvotes: 4

Related Questions