Java8总结为流

时间:2016-11-12 15:02:28

标签: hashmap java-8 java-stream

我有这个LinkedHashMap:

myMap = {
  0 => 10,
  1 => 6,
  2 => 28,
  ...
}
int limit = 15;

我想要使用流做的是对(按顺序)求和地图值,并在达到限制时停止,并返回地图中的相应索引(在本例中为0)。 流有优雅的方式吗?

2 个答案:

答案 0 :(得分:1)

你总结到这样的限制

myMap.values().reduce(0, (a, b) -> a+b > limit ? a : a + b);

答案 1 :(得分:1)

可以通过我的免费StreamEx库扩展标准Stream API,但即使使用库也不是很优雅:

EntryStream.of(myMap) // like myMap.entrySet().stream()
    .prefix(
       (e1, e2) -> new AbstractMap.SimpleEntry<>(e2.getKey(), e1.getValue() + e2.getValue()))
    .takeWhile(e -> e.getValue() < limit)
    .reduce((a, b) -> b)
    .ifPresent(System.out::println);

这里我们使用两个特殊的StreamEx操作。一个是prefix,它懒惰地计算运行前缀(如Haskell中的scanl)。这里有两个条目,我们选择后一个的键和它们的值的总和,创建一个新条目。接下来,我们使用takeWhile(也将出现在Java 9标准Stream API中)在值超出限制时立即停止。最后,我们减少到最后找到的元素并打印它,如果它存在,所以我们不仅索引,而且还打印最终总和(如果你只需要索引,添加.map(Entry::getKey)步骤。)

虽然这样的解决方案是无用的FP-ish我不推荐它一般,因为它不是非常有效并且产生垃圾(中间条目和盒装整数),更不用说外部库依赖。使用普通旧循环。它高效且易于理解:

int sum = 0;
Integer lastKey = null;
for(Map.Entry<Integer, Integer> e : myMap.entrySet()) {
    sum+=e.getValue();
    if(sum >= limit) break;
    lastKey = e.getKey();
}
if(lastKey != null) {
    System.out.println(lastKey);
}