2016-11-12 33 views
2

我有这样的LinkedHashMap:Java8总结与流的限制

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

我会想使用流是总结(按顺序)的映射值做,并停止达到限制时,并返回地图中的相应索引(在这种情况下为0)。 有没有一个优雅的方式与流?

+4

我没有看到任何。总是有办法做到这一点,但是与简单的循环相比,这将是人为设计的。 Justa问题,为什么你使用LinkedHashMap而不是List,因为你的键是索引? –

+0

@Andrea,java 8没有'takeWhile'操作来执行某些操作,例如*“在达到限制时停止”* – Andrew

+0

应该返回什么内容,例如,示例中的5和100? – Tunaki

回答

0

你可以总结到了一个极限这样

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

它通过延伸的标准流API我免费StreamEx库的可能,但即使与库它不是很优雅:

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我不会推荐它在一般情况下,因为它不是很有效,并产生垃圾(中间条目和盒装整数),更不用说外部库依赖。使用普通的旧for循环。这是有效的和易于理解的:

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); 
}