事实上,您要找的只是一个查找表,可以将行星映射到一组兼容的物种。如果使用“映射”类(仅因为Java没有任何类型感知的元组式数据结构而需要此类),则很容易实现,如下所示:
public static class PlanetSpecies {
Planet planet;
Set<Species> species;
public PlanetSpecies(Planet planet, Set<Species> species) {
this.planet = planet;
this.species = species;
}
public Planet getPlanet() {
return planet;
}
public Set<Species> getSpecies() {
return species;
}
}
使用这种方式,您可以轻松地从这两个集合中构建一个
PlanetSpecies
集合:
Set<PlanetSpecies> planetSpecies = Stream
.of(new Planet("blue planet", 45),
new Planet("red planet", 150),
new Planet("green planet", 77))
.map(speciesMapper)
.collect(Collectors.toSet());
这将导致以下输出,基本上是您原始行星列表映射到其兼容物种的集合:
[ {
"planet" : {
"name" : "blue planet",
"temp" : 45
},
"species" : [ {
"lower" : 5,
"upper" : 70
} ]
}, {
"planet" : {
"name" : "green planet",
"temp" : 77
},
"species" : [ {
"lower" : 75,
"upper" : 80
} ]
}, {
"planet" : {
"name" : "red planet",
"temp" : 150
},
"species" : [ {
"lower" : 100,
"upper" : 220
} ]
} ]
这在某种意义上意味着您不需要“分组”。
然而,如果您需要的结果类似于Map<planet_name, Set<Species>>
,则需要做更多工作:
Map<String, Set<Species>> planetSpecies = Stream
.of(new Planet("blue planet", 45),
new Planet("red planet", 150),
new Planet("green planet", 77))
.map(speciesMapper)
.collect(
Collectors.groupingBy(
(PlanetSpecies sp) -> sp.getPlanet().getName(),
Collectors.mapping(species -> species.getSpecies(),
Collectors.reducing(new HashSet<Species>(), speciesReducer)
)
));
使用reducer声明如下:
BinaryOperator<Set<Species>> speciesReducer = (set1, set2) -> {
Set<Species> newSet = new HashSet<>();
newSet.addAll(set1);
newSet.addAll(set2);
return newSet;
};
这个reducer基本上在执行一个set.union操作。
以上代码将产生以下输出:
{
"green planet" : [ {
"lower" : 75,
"upper" : 80
} ],
"blue planet" : [ {
"lower" : 5,
"upper" : 70
} ],
"red planet" : [ {
"lower" : 100,
"upper" : 220
} ]
}