型号:
public class AgencyMapping {
private Integer agencyId;
private String scoreKey;
}
public class AgencyInfo {
private Integer agencyId;
private Set<String> scoreKeys;
}
我的代码:
List<AgencyMapping> agencyMappings;
Map<Integer, AgencyInfo> agencyInfoByAgencyId = agencyMappings.stream()
.collect(groupingBy(AgencyMapping::getAgencyId,
collectingAndThen(toSet(), e -> e.stream().map(AgencyMapping::getScoreKey).collect(toSet()))))
.entrySet().stream().map(e -> new AgencyInfo(e.getKey(), e.getValue()))
.collect(Collectors.toMap(AgencyInfo::getAgencyId, identity()));
有没有办法获得相同的结果并使用更简单的代码更快?
答案 0 :(得分:4)
您可以通过调用collectingAndThen(toSet(), e -> e.stream().map(AgencyMapping::getScoreKey).collect(toSet()))))
来简化对mapping(AgencyMapping::getScoreKey, toSet())
的通话。
Map<Integer, AgencyInfo> resultSet = agencyMappings.stream()
.collect(groupingBy(AgencyMapping::getAgencyId,
mapping(AgencyMapping::getScoreKey, toSet())))
.entrySet()
.stream()
.map(e -> new AgencyInfo(e.getKey(), e.getValue()))
.collect(toMap(AgencyInfo::getAgencyId, identity()));
使用toMap
收集器查看它的另一种方法:
Map<Integer, AgencyInfo> resultSet = agencyMappings.stream()
.collect(toMap(AgencyMapping::getAgencyId, // key extractor
e -> new HashSet<>(singleton(e.getScoreKey())), // value extractor
(left, right) -> { // a merge function, used to resolve collisions between values associated with the same key
left.addAll(right);
return left;
}))
.entrySet()
.stream()
.map(e -> new AgencyInfo(e.getKey(), e.getValue()))
.collect(toMap(AgencyInfo::getAgencyId, identity()));
后一个例子可能比前者复杂得多。然而,如上所述,您的方法几乎是使用mapping
而不是collectingAndThen
的方法。
除此之外,我没有看到任何其他可以通过显示的代码简化的内容。
对于更快的代码,如果您建议当前的方法性能较慢,那么您可能需要阅读答案here,该答案会在您考虑时考虑并行。
答案 1 :(得分:1)
您正在收集到中间地图,然后将此地图的条目流式传输以创建AgencyInfo
个实例,这些实例最终会被收集到另一个地图中。
您可以使用Collectors.toMap
直接收集地图,将每个AgencyMapping
对象映射到所需的AgencyInfo
并根据需要合并scoreKeys
,而不是所有这些:
Map<Integer, AgencyInfo> agencyInfoByAgencyId = agencyMappings.stream()
.collect(Collectors.toMap(
AgencyMapping::getAgencyId,
mapping -> new AgencyInfo(
mapping.getAgencyId(),
new HashSet<>(Set.of(mapping.getScoreKey()))),
(left, right) -> {
left.getScoreKeys().addAll(right.getScoreKeys());
return left;
}));
这可以通过AgencyMapping
对流的AgencyMapping::getAgencyId
元素进行分组,但在地图中存储AgencyInfo
个对象。我们通过手动映射每个原始AgencyInfo
对象来获取这些AgencyMapping
个实例。最后,我们通过合并函数合并AgencyInfo
已经在地图中的scoreKeys
个实例,向左折叠 AgencyInfo
Set.of
Collections.singleton
1}}到另一个。
我正在使用Java 9的subject = await Subject.find({ name: 'Math' });
来创建单例集。如果您没有Java 9,则可以将其替换为Subject.find({name: 'Math'})
。