Java Streams - 获取“对称差异列表”来自另外两个名单 [英] Java Streams - Get a "symmetric difference list" from two other lists

查看:114
本文介绍了Java Streams - 获取“对称差异列表”来自另外两个名单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用Java 8流来组合列表。
如何从两个现有列表中获得对称差异列表(仅存在于一个列表中的所有对象)。
我知道如何获得交叉列表以及如何获得联合列表。

Im trying to use Java 8 streams to combine lists. How can I get a "symmetric difference list" (all object that only exist in one list) from two existing lists. I know how to get an intersect list and also how to get a union list.

在下面的代码中,我想要从两个列表中找到不相交的汽车cars(bigCarList,smallCarList)。
我希望结果是2辆车的列表(丰田卡罗拉和福特福克斯)

In the code below I want the disjoint Cars from the two lists of cars (bigCarList,smallCarList). I expect the result to be a list with the 2 cars ("Toyota Corolla" and "Ford Focus")

示例代码:

public void testDisjointLists() {
    List<Car> bigCarList = get5DefaultCars();
    List<Car> smallCarList = get3DefaultCars();

    //Get cars that exists in both lists
    List<Car> intersect = bigCarList.stream().filter(smallCarList::contains).collect(Collectors.toList());

    //Get all cars in both list as one list
    List<Car> union = Stream.concat(bigCarList.stream(), smallCarList.stream()).distinct().collect(Collectors.toList());

    //Get all cars that only exist in one list
    //List<Car> disjoint = ???

}

public List<Car> get5DefaultCars() {
    List<Car> cars = get3DefaultCars();
    cars.add(new Car("Toyota Corolla", 2008));
    cars.add(new Car("Ford Focus", 2010));
    return cars;
}

public List<Car> get3DefaultCars() {
    List<Car> cars = new ArrayList<>();
    cars.add(new Car("Volvo V70", 1990));
    cars.add(new Car("BMW I3", 1999));
    cars.add(new Car("Audi A3", 2005));
    return cars;
}

class Car {
    private int releaseYear;
    private String name;
    public Car(String name) {
        this.name = name;
    }
    public Car(String name, int releaseYear) {
        this.name = name;
        this.releaseYear = releaseYear;
    }

    //Overridden equals() and hashCode()
}


推荐答案

根据您自己的代码,有一个直接的解决方案:

Based on your own code, there is a straight-forward solution:

List<Car> disjoint = Stream.concat(
    bigCarList.stream().filter(c->!smallCarList.contains(c)),
    smallCarList.stream().filter(c->!bigCarList.contains(c))
).collect(Collectors.toList());

只需为另一个未包含的所有项目筛选一个列表,反之亦然,并连接两个结果。这对于小型列表非常有效,并且在考虑优化解决方案(如散列或使结果 distinct()之前,如果您不想要这两个列表,您应该问自己为什么使用列表,重复或特定订单。

Just filter one list for all items not contained in the other and vice versa and concatenate both results. That works fairly well for small lists and before consider optimized solutions like hashing or making the result distinct() you should ask yourself why you are using lists if you don’t want neither, duplicates nor a specific order.

看起来你真的想要设置 s,而不是列表秒。如果您使用设置,则 Tagir Valeev的解决方案是合适的。但是它没有使用 List 的实际语义,即如果源列表包含重复项则不起作用。

It seems like you actually want Sets, not Lists. If you use Sets, Tagir Valeev’s solution is appropriate. But it is not working with the actual semantics of Lists, i.e. doesn’t work if the source lists contain duplicates.

但如果你使用 Set s,代码可以更简单:

But if you are using Sets, the code can be even simpler:

Set<Car> disjoint = Stream.concat(bigCarSet.stream(), smallCarSet.stream())
  .collect(Collectors.toMap(Function.identity(), t->true, (a,b)->null))
  .keySet();

这使用 toMap 收集器创建一个 Map (该值无关紧要,我们只需映射到 true )并使用合并函数来处理重复项。因为对于两个集合,重复只能在两个集合中包含项目时发生,这些是我们想要删除的项目。

This uses the toMap collector which creates a Map (the value is irrelevant, we simply map to true here) and uses a merge function to handle duplicates. Since for two sets, duplicates can only occur when an item is contained in both sets, these are the items we want remove.

的文档Collectors.toMap 表示合并函数被视为提供给 Map.merge(Object,Object,BiFunction) 我们可以从中学习只需将副本映射到 null ,就会删除该条目。

The documentation of Collectors.toMap says that the merge function is treated "as supplied to Map.merge(Object, Object, BiFunction)" and we can learn from there, that simply mapping the duplicate pair to null will remove the entry.

之后,<$ c映射的$ c> keySet()包含不相交集。

这篇关于Java Streams - 获取“对称差异列表”来自另外两个名单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆