Skip to content
Advertisement

Remove numbers from a list that begins with a specif digit

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 the List interface. One accepts an int index another an object that has to be removed. And this case is interesting because it is a choice between remove(int) and remove(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. method remove(int) will be invoked since we are passing a primitive type int.

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]
Advertisement