2016-11-12 50 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); 
}