简体   繁体   English

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

[英]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 present in another list (cars2) using java stream.如果存在于另一个列表 (cars2) 中,我正在尝试使用 java 流删除一个列表 (cars1) 的元素(在我的情况下为 Cars)。 I tried using removeIf but then it felt like it works more appropriately with List of Strings, etc.我尝试使用 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

If methods hashCode and equals are properly implemented in class Car , the stream-based solutions may look as follows:如果在类Car中正确实现了hashCodeequals方法,则基于流的解决方案可能如下所示:

  • 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 ):
cars2.forEach(cars1::remove); 
// no need to call cars2.stream().forEach(cars1::remove);

Here the first occurrence of Car instance is removed in cars1这里第一次出现的 Car 实例在cars1被删除

  • removeIf should work also removeIf也应该工作
cars1.removeIf(cars2::contains);

If you due to some reason equals / hashCode are not overridden in class Car , the following solution may be offered:如果您由于某种原因在类Car中没有覆盖equals / hashCode ,则可能会提供以下解决方案:

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 : removeIf
cars1.removeIf(c1 -> cars2
    .stream()
    .anyMatch(c2 -> c1.getId() == c2.getId() 
        && Objects.equals(c1.getName(), c2.getName())
    )
);

It can be done simply by using removeAll() method.只需使用 removeAll() 方法即可完成。 You have to implement hashcode and equals in Car class.您必须在 Car 类中实现 hashcode 和 equals。 Then you can cars1.removeAll(cars2);然后你可以cars1.removeAll(cars2); . . this statement would leave only c1 in cars1 list.这个语句只会在cars1 列表中留下c1。

The recommended solution is to override toString and hasCode() methods in the class, Car and then you can, as already comment below the question, do something like推荐的解决方案是覆盖类Car中的toStringhasCode()方法,然后您可以像问题下面已经评论的那样,执行类似的操作

cars1.removeAll(cars2);

or或者

cars1.removeIf(cars2::contains);

However, if these two methods are not overridden in the class, Car , you will have to compare each attribute within the nested loops.但是,如果这两个方法在类Car中没有被覆盖,则必须比较嵌套循环中的每个属性。 This approach is only useful to learn nested loops and is never recommended for production use.这种方法只对学习嵌套循环有用,从不推荐用于生产。

Demo:演示:

import java.util.ArrayList;
import java.util.List;

class Car {
    int id;
    String name;

    @Override
    public String toString() {
        return "Car [id=" + id + ", name=" + name + "]";
    }
}

public class Main {
    public static void main(String[] args) {
        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);

        for (int i = 0; i < cars1.size(); i++) {
            Car car1 = cars1.get(i);
            for (int j = 0; j < cars2.size(); j++) {
                Car car2 = cars2.get(j);
                if (car2.id == car1.id && car2.name.equals(car1.name))
                    cars1.remove(i);
            }
        }

        System.out.println(cars1);
    }
}

Output:输出:

[Car [id=1, name=C1]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM