使用流删除一个列表中的元素(如果存在于另一个列表中)

Tiy*_*iya -1 java remove-if java-stream

我在这里没有找到任何关于这个问题的线索。我正在尝试使用 java 流删除一个列表 (cars1) 中存在于另一个列表 (cars2) 中的元素(在我的例子中为汽车)。我尝试使用removeIf,但后来感觉它更适合字符串列表等。

    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
Run Code Online (Sandbox Code Playgroud)

Ale*_*nko 8

如果方法hashCodeequals在类中正确实现Car,基于流的解决方案可能如下所示:

  • 过滤掉值,收集到一个新列表中
// 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());

Run Code Online (Sandbox Code Playgroud)
  • 用于forEachcars2影响cars1):
cars2.forEach(cars1::remove); 
// no need to call cars2.stream().forEach(cars1::remove);
Run Code Online (Sandbox Code Playgroud)

这里第一次出现的 Car 实例被删除cars1

  • removeIf也应该有效
cars1.removeIf(cars2::contains);
Run Code Online (Sandbox Code Playgroud)

如果您由于某种原因equals/hashCode在课堂上没有被覆盖Car,可能会提供以下解决方案:

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