For example, i have this list
List<Integer> list = new ArrayList<>(); list.add(64); list.add(5); list.add(10); list.add(66); list.add(7); list.add(68);
How i remove only the numbers that begins with “6”
Advertisement
Answer
There are several ways how you can approach this task:
- using an
Iterator
; - by utilizing so-called traditional for loop;
- with a help of Stream IPA;
- using method
Collection.removeIf()
.
Note that attempt to address this problem using enhanced for loop (sometimes called “for-each” loop) will lead to CuncurrentModdificationException
at runtime (if the collection will get modified). Because under hood iteration over a collection with enhanced for loop makes use of an iterator that is provided by the collection. And while iteration happens collection must not be modified other than by means of the iterator itself, i.e. by using method remove()
of the iterator.
To iterate over the collection with an iterator firstly you have to an instance of the Iterator
by invoking .iterator()
on the collection. Methods of the Iterator
class hasNext()
and next()
are used to check whether the next element exists and to move to the next element respectively.
public static List<Integer> removeNumberIfStarsWith(List<Integer> source, int target) { List<Integer> copy = new ArrayList<>(source); // defencive copy to preserve the source list intact Iterator<Integer> iterator = copy.iterator(); while (iterator.hasNext()) { Integer item = iterator.next(); if (item.toString().startsWith(String.valueOf(target))) { iterator.remove(); } } return copy; }
To implement this task with traditional for loop we have to keep in mind that removal of elements must not mess the indices that are haven’t visited yet. Probably the simplest way to do it is to iterate in reversed order starting from the last index.
Note:
- there are two flavors of
remove()
method available with an instance of theList
interface. One accepts anint
index another anobject
that has to be removed. And this case is interesting because it is a choice betweenremove(int)
andremove(Integer)
. Remember that when an overloaded method is called if a version of this method with exactly the same set of parameter types (same types in the same order) exists, the compiler will map this version to that method call. I.e. methodremove(int)
will be invoked since we are passing a primitive typeint
.
The code for this task with traditional for loop might look like:
public static List<Integer> removeNumberIfStarsWith(List<Integer> source, int target) { List<Integer> copy = new ArrayList<>(source); // defencive copy to preserve the source list intact for (int i = copy.size() - 1; i >= 0; i--) { Integer item = copy.get(i); if (item.toString().startsWith(String.valueOf(target))) { copy.remove(i); } } return copy; }
Since this question is related to basic operations with collections I don’t assume the knowledge of lambda expressions and streams. But for completeness and for future readers, I’ll provide two other options that I’ve mentioned above.
for information on lambda expressions and functional interfaces read this
to get familiar with Stream IPA take a look at this tutorial
The condition inside the method filter()
in the stream pipeline and Collection.removeIf()
must defenetelly look familiar to you. Both method expect Predicate
a function that takes an object and returns a boolean value. Collection.removeIf()
will remove the element if the predicate returns true
, but filter()
does the opposite it’ll retain the element if the predicate returns true
.
So stream-based implementation might look like this:
public static List<Integer> removeNumberIfStarsWith(List<Integer> source, int target) { return source.stream() .filter(item -> !item.toString().startsWith(String.valueOf(target))) .collect(Collectors.toList()); }
Solution with Collection.removeIf()
:
public static List<Integer> removeNumberIfStarsWith(List<Integer> source, int target) { List<Integer> copy = new ArrayList<>(source); // defencive copy to preserve the source list intact copy.removeIf(item -> item.toString().startsWith(String.valueOf(target))); return copy; }
main()
public static void main(String[] args) { List<Integer> list = List.of(64, 5, 10, 66, 7, 68); System.out.println(list); System.out.println(removeNumberIfStarsWith(list, 6)); // value 6 provided as an argument and not hardcoded inside the methods }
Output (for all the versions)
[64, 5, 10, 66, 7, 68] [5, 10, 7]