Home > Software design >  Remove elements from a List at a specific index
Remove elements from a List at a specific index

Time:06-04

I am trying to program a method that deletes the first, second and third element of every group of 4 elements. It seems not working at all. Could anyone please help?

public static void reduziereKommentare(List<String> zeilen) {
        if (!zeilen.isEmpty()) {
            if (zeilen.size() % 4 != 0) {
                throw new RuntimeException("Illegal size "   zeilen.size()   " of list, must be divisible by 4.");
            }
            for (int i = 1; i <= zeilen.size() % 4; i  ) {
                zeilen.remove(i);
                zeilen.remove(i   1);
                zeilen.remove(i   2);
            }
        }
        System.out.println(zeilen);
    }

CodePudding user response:

As said in the comments, removing an element impacts the indexing. Whenever I need to do something like this, I either use an Iterator, or loop backwards.:

for (int i = zeilen.size() - 4; i >= 0; i -= 4) {
    zeilen.remove(i   2);
    zeilen.remove(i   1);
    zeilen.remove(i);
}

Note that I subtract 4 from i each iteration, so I go back a full block of four each time.

Also note that I remove the largest indexed elements first. If I use i, i 1 and i 2 inside the loop, I again run into the same issue. I could also have used i 3 times, but this makes it more clear.

CodePudding user response:

My take...does not require the size precondition check but you may want to still catch that if it represents an error of broader scope than this method.

Given this test code...

    // Test code
    List<String> myList = new ArrayList<>();
    for (int i = 0; i < 20; i  ) {
        myList.add(String.valueOf(i));
    }
    

the 'zeilen' loop can be implemented as ...

    // "before" diagnostics
    System.out.println(zeilen);

    // The 'zeilen' loop
    for (int i = 0, limit = zeilen.size(); i < limit; i  ) {
        if ((i 1) % 4 > 0) zeilen.remove(i/4);
    }

    // "after" diagnostics
    System.out.println(zeilen);

and produces

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[3, 7, 11, 15, 19]

Works with any length list leaving every '4th' element in list.

A few more test cases :

Given                   Results in
[]                      []
[0,1]                   []
[0,1,2,3]               [3]
[0,1,2,3,4]             [3]
[0,1,2,3,4,5,6,7]       [3,7]
[0,1,2,3,4,5,6,7,8]     [3,7]

CodePudding user response:

Would it not be easier to simply add every fourth item to a new list and return that? This would also eliminate any repetitive copying that could be involved when removing elements from a list. And the target list can be appropriately sized to start.

public static List<String> reduziereKommentare(List<String> zeilen) {
    Objects.requireNonNull(zeilen);
    List<String> zeilen1= new ArrayList<>(zeilen.size()/4);

    for(int i = 3; i < zeilen.size(); i =4) {
            zeilen1.add(zeilen.get(i));
    }

    return zeilen1;
}

You could also use a stream.


zeilen = IntStream.iterate(3, i ->i < zeilen.size(), i->i =4)
                .mapToObj(zeilen::get).toList();

Notes:

  • whether the list is empty or the size is not divisible by 4, this will work. It will just ignore the extra elements.
  • assigning the result to the original variable will result in the old list being garbage collected.
  • I only check for a null argument since that would cause an exception. Of course, if alerting the user of the size is important just add the other check(s) back in.
  • Related