Java 8 Stream - 对Collection中具有相同id的对象的操作

时间:2016-10-14 15:46:17

标签: java collections java-8 java-stream

我的问题有点复杂(我认为),所以我会尝试使用一个例子。希望你能理解我的问题。

设置说我有一个用户列表:

List<User> users;

其中:

public class User{
    private List<Car> cars;
}

public class Car{
    private String code;
    private List<Feature> features;
}

public class Feature{
    private String code;
}

我想要实现的是从用户列表中获取汽车列表但我也希望这个列表是不同的(没有相同代码的汽车)但我希望单个Car对象具有来自的所有功能具有相同代码的不同汽车以及我失败的地方。

现在我有

List<Car> cars = users
        .stream()
        .flatMap(user -> user.getCars())
        .???

我知道我可以使用Predicate通过代码过滤汽车,但我很难为我要离开的那些添加功能。是否有一种干净的方式来做流?

1 个答案:

答案 0 :(得分:2)

这一切归结为一个问题,你想如何获得Car拥有所有联合功能。您肯定不想修改其中一个Car的任意User实例。因此,为了支持加入这些Feature,您必须在加入功能列表后构建新的Car实例。

这可以按如下方式完成:

List<Car> cars =
    users.stream()
    .flatMap(user -> user.getCars().stream())
    .collect(Collectors.groupingBy(Car::getCode,
        Collectors.mapping(Car::getFeatures, Collector.of(
            ArrayList<Feature>::new, List::addAll, (a,b)->{a.addAll(b);return a;}))))
    .entrySet().stream()
    .map(e -> new Car(e.getKey(), e.getValue()))
    .collect(Collectors.toList());

有两个步骤。第一个使用code属性作为键执行分组操作,并将组中所有Feature的{​​{1}}列表加入一个Car
这会产生List。第二步将每个映射表项转换为新的Map<String,List<Feature>>实例,假设有Car构造函数。这些结果Car(String code, List<Feature> features)个实例会收集到Car

请注意,上面的代码只是将所有List列表连接到一个列表。如果您必须从这些列表中删除重复的Feature,则可以使用

Feature

这首先将List<Car> cars = users.stream() .flatMap(user -> user.getCars().stream()) .collect(Collectors.groupingBy(Car::getCode, Collectors.mapping(Car::getFeatures, Collector.of( LinkedHashSet<Feature>::new, Set::addAll, (a,b)->{a.addAll(b);return a;})))) .entrySet().stream() .map(e -> new Car(e.getKey(), new ArrayList<>(e.getValue()))) .collect(Collectors.toList()); 的{​​{1}}个FeatureCar相同的code收集到Set,删除重复但保留订单(对于相关的情况)和在构造结果Set实例时,将List转换为Car