Search code examples
javajava-streamremove-if

Removing elements of one list if present in another list using stream


I didn't find any thread here on this Question. I am trying to Remove elements (Cars in my case) of one list (cars1) if they present in another list (cars2) using Java stream.

I tried using removeIf but then it felt like it works more appropriately with List of Strings, etc. instead of objects.

Imagine the sample codes below:

    Car c1 = new Car();
    c1.id = 1;
    c1.name = "C1";

    Car c2 = new Car();
    c2.id = 2;
    c2.name = "C2";

    List<Car> cars1 = new ArrayList<Car>();
    cars1.add(c1);
    cars1.add(c2);

    List<Car> cars2 = new ArrayList<Car>();
    cars2.add(c2);

    // TODO : Remove all the cars from cars1 list that are in cars2 list using java streams

How to remove all the cars from cars1 list that are present in cars2 list using java streams?


Solution

  • If methods hashCode and equals are properly implemented in class Car, the stream-based solutions may look as follows:

    • filter out the values, collect into a new list
    // Predicate.not added in Java 11
    List<Car> notJava11 = cars1.stream()
                            .filter(Predicate.not(cars2::contains))
                            .collect(Collectors.toList());
    
    List<Car> notIn2 = cars1.stream()
                            .filter(car -> !cars2.contains(car))
                            .collect(Collectors.toList());
    
    
    • Use forEach for cars2 (affecting cars1):
    cars2.forEach(cars1::remove); 
    // no need to call cars2.stream().forEach(cars1::remove);
    

    Here the first occurrence of Car instance is removed in cars1

    • removeIf should work also
    cars1.removeIf(cars2::contains);
    

    If you due to some reason equals/hashCode are not overridden in class Car, the following solution may be offered:

    List<Car> notIn2 = cars1
            .stream()
            .filter(c1 -> cars2
                .stream()
                .noneMatch(c2 -> 
                     c1.getId() == c2.getId()
                     && Objects.equals(c1.getName(), c2.getName())
                )
            )
            .collect(Collectors.toList());
    
    • removeIf:
    cars1.removeIf(c1 -> cars2
        .stream()
        .anyMatch(c2 -> c1.getId() == c2.getId() 
            && Objects.equals(c1.getName(), c2.getName())
        )
    );