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

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

我在这里没有找到关于这个问题的任何线索。如果存在于另一个列表 (cars2) 中,我正在尝试使用 java 流删除一个列表 (cars1) 的元素(在我的例子中为 Cars)。 我尝试使用 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

如果方法 hashCodeequals 在 class 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());

  • cars2使用forEach(影响cars1):
cars2.forEach(cars1::remove); 
// no need to call cars2.stream().forEach(cars1::remove);

此处第一个出现的 Car 实例在 cars1

中被删除
  • removeIf 应该也可以
cars1.removeIf(cars2::contains);

如果你因为某些原因 equals/hashCode 没有在 class 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());
  • removeIf:
cars1.removeIf(c1 -> cars2
    .stream()
    .anyMatch(c2 -> c1.getId() == c2.getId() 
        && Objects.equals(c1.getName(), c2.getName())
    )
);

只需使用 removeAll() 方法即可完成。您必须在 Car class 中实现 hashcode 和 equals。 然后就可以cars1.removeAll(cars2);了。此语句将仅在 cars1 列表中留下 c1。