Java流合并或减少重复的对象

Vku*_*Vku 8 java reduce merge list java-stream

我需要通过将所有重复的条目合并到一个对象中从列表中生成一个唯一的朋友列表可以有重复项
示例 - 从不同的社交订阅源获取朋友并将其放入1个大列表中
1.朋友 - [姓名:"Johnny Depp", dob:"1970-11-10",来源:"FB",fbAttribute:".."]
2.朋友 - [姓名:"Christian Bale",dob:"1970-01-01",来源:"LI" ,liAttribute:".."]
3.朋友 - [姓名:"Johnny Depp",dob:"1970-11-10",来源:"Twitter",twitterAttribute:".."]
4.朋友 - [姓名: "Johnny Depp",dob:"1970-11-10",来源:"LinkedIn",liAttribute:".."]
5.朋友 - [姓名:"Christian Bale",dob:"1970-01-01",来源:"LI",liAttribute:".."]

预期输出
1.朋友 - [姓名:"Christian Bale",dob:"1970-01-01",liAttribute:"..",fbAttribute:"..",twitterAttribute:".."]
2.朋友 - [名称:"Johnny Depp",dob:"1970-11-10",liAttribute:"..",fbAttribute:"..",twitterAttribute:".."]

问题 - 如何在不使用任何中间容器的情况下合并?我可以轻松地使用中间映射并对条目的每个值应用reduce.

List<Friend> friends;
Map<String, List<Friend>> uniqueFriendMap
    = friends.stream().groupingBy(Friend::uniqueFunction);
List<Friend> mergedFriends = uniqueFriendMap.entrySet()
    .stream()
    .map(entry -> {
           return entry.getValue()
                .stream()
                .reduce((a,b) -> friendMergeFunction(a,b));
    })
    .filter(mergedPlace -> mergedPlace.isPresent())
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

我喜欢这样做而不使用中间Map uniqueFriendMap.有什么建议?

Hol*_*ger 10

groupingBy操作(或类似的操作)是不可避免的,Map操作创建的操作也在查找分组键和查找重复项的操作期间使用.但是你可以将它与组元素的减少结合起来:

Map<String, Friend> uniqueFriendMap = friends.stream()
    .collect(Collectors.groupingBy(Friend::uniqueFunction,
        Collectors.collectingAndThen(
            Collectors.reducing((a,b) -> friendMergeFunction(a,b)), Optional::get)));
Run Code Online (Sandbox Code Playgroud)

地图的价值已经是由此产生的不同朋友.如果您确实需要a List,可以使用普通的Collection操作创建它:

List<Friend> mergedFriends = new ArrayList<>(uniqueFriendMap.values());
Run Code Online (Sandbox Code Playgroud)

如果第二次操作仍然让您烦恼,可以在collect操作中隐藏它:

List<Friend> mergedFriends = friends.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Friend::uniqueFunction, Collectors.collectingAndThen(
            Collectors.reducing((a,b) -> friendMergeFunction(a,b)), Optional::get)),
        m -> new ArrayList<>(m.values())));
Run Code Online (Sandbox Code Playgroud)

但请注意,即使在您的原始方法中,也可以进行多种简化.当您只处理a的值时toMap,您不需要使用friendMergeFunction,这需要您调用static每个条目.你可以(a,b) -> friendMergeFunction(a,b)在第一时间处理它.然后,您不需要详细DeclaringClass::friendMergeFunction语法,this::friendMergeFunction就足够了.由于前面的分组操作的组不能为空,因此过滤步骤已过时.所以你原来的方法看起来像:

List<Friend> mergedFriends = friends.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(Friend::uniqueFunction, Function.identity(),
            (a,b) -> friendMergeFunction(a,b)),
        m -> new ArrayList<>(m.values())));
Run Code Online (Sandbox Code Playgroud)

这不是那么糟糕.如上所述,融合操作不会跳过Map创建,因为这是不可避免的.它只会跳过entrySet()代表每个组的s 的创建,因为它会将它们缩减为单个getValue()就地.