我需要通过将所有重复条目合并到一个对象中,从列表中生成一个可以有重复项的唯一好友列表
示例 - 将朋友从不同的社交Feed中提取并放入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:&#34 ; ...",twitterAttribute:" .."]
2.朋友 - [姓名:" Johnny Depp",dob:" 1970-11-10",liAttribute:" ..",fbAttribute:&#34 ; ...",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());
我喜欢在不使用中间Map uniqueFriendMap的情况下执行此操作。有什么建议吗?
答案 0 :(得分:9)
groupingBy
操作(或类似的操作)是不可避免的,操作创建的Map
也在操作期间用于查找分组键并查找重复项。但是你可以将它与组元素的减少结合起来:
Map<String, Friend> uniqueFriendMap = friends.stream()
.collect(Collectors.groupingBy(Friend::uniqueFunction,
Collectors.collectingAndThen(
Collectors.reducing((a,b) -> friendMergeFunction(a,b)), Optional::get)));
地图的价值已经是由此产生的不同朋友。如果您确实需要List
,可以使用普通的Collection操作创建它:
List<Friend> mergedFriends = new ArrayList<>(uniqueFriendMap.values());
如果第二次操作仍然让您烦恼,可以在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())));
但请注意,即使在原始方法中,也可以进行多种简化。如果您只处理Map
的值,则无需使用entrySet()
,这需要您在每个条目上调用getValue()
。您可以首先处理values()
。然后,您不需要详细的input -> { return expression; }
语法,因为input -> expression
就足够了。由于前面的分组操作的组不能为空,因此过滤步骤已过时。所以你原来的方法看起来像:
Map<String, List<Friend>> uniqueFriendMap
= friends.stream().collect(Collectors.groupingBy(Friend::uniqueFunction));
List<Friend> mergedFriends = uniqueFriendMap.values().stream()
.map(group -> group.stream().reduce((a,b) -> friendMergeFunction(a,b)).get())
.collect(Collectors.toList());
这不是那么糟糕。如上所述,融合操作不会跳过Map
创建,因为这是不可避免的。它只会跳过代表每个组的List
s的创建,因为它会将它们缩减为单个Friend
。
答案 1 :(得分:2)
只需使用方法Collectors.frequency
。