是的,您可以使用流操作来实现这一点,但我建议为这些数据创建一个类,以便每一行对应一个特定实例。这将使您的生活更轻松 IMO。
class Data {
private int id;
private Map<String, List<Integer>> map;
....
}
也就是说,让我们来看看如何实现这一点。一、find all的实现:
public static Set<Integer> ids(List<Data> list, String value, Predicate<Integer> boundPredicate) {
return list.stream()
.filter(d -> d.getMap().containsKey(value))
.filter(d -> d.getMap().get(value).stream().anyMatch(boundPredicate))
.map(d -> d.getId())
.collect(toSet());
}
这本书读起来很简单。您会从列表中获得Stream<Data>。然后你应用一个过滤器,这样你只得到具有映射中给定值的实例,并且有一个值满足你给定的谓词。然后将每个实例映射到其对应的 id,并在 Set 中收集结果流。
调用示例:
Set<Integer> set = ids(list, "a", value -> value < 3);
哪个输出:
[1, 2, 3]
平均请求有点棘手。我最终得到了另一个实现,最后你最终得到了一个Map<String, IntSummaryStatistics>(其中确实包含平均值)以及其他信息。
Map<String, IntSummaryStatistics> stats = list.stream()
.flatMap(d -> d.getMap().entrySet().stream())
.collect(toMap(Map.Entry::getKey,
e -> e.getValue().stream().mapToInt(i -> i).summaryStatistics(),
(i1, i2) -> {i1.combine(i2); return i1;}));
你首先得到一个Stream<Data>,然后你flatMap每个映射的每个条目集都有Stream<Entry<String, List<Integer>>。现在您将此流收集到一个映射中,其中每个键都由条目的键映射,每个List<Integer> 都由其对应的IntSummaryStatistics 值映射。如果您有两个相同的键,则组合它们各自的 IntSummaryStatistics 值。
给定你的数据集,你会得到一个Map<String, IntSummaryStatistics>
ff => IntSummaryStatistics{count=1, sum=3, min=3, average=3.000000, max=3}
bb => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
a => IntSummaryStatistics{count=5, sum=11, min=1, average=2.200000, max=3}
b => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
c => IntSummaryStatistics{count=2, sum=6, min=2, average=3.000000, max=4}
d => IntSummaryStatistics{count=1, sum=3, min=3, average=3.000000, max=3}
e => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
您可以轻松地从中获取平均值。
这里有一个完整的working example,不过实现当然可以改进。