簡體   English   中英

對String數組進行分組依據和求和運算

[英]Group by and sum operation on a String array

我有一個String[] dataValues如下:

ONE:9
TWO:23
THREE:14
FOUR:132
ONE:255
TWO:727
FIVE:3
THREE:196
FOUR:1843
ONE:330
TWO:336
THREE:190
FOUR:3664

我想要總計ONETWOTHREEFOURFIVE

所以我創建了一個HashMap

Map<String, Integer> totals = new HashMap<String, Integer>();
for(String dataValue : dataValues){
    String[] keyVal = dataValue.split(":");
      totals.put(keyVal[0], totals.get(keyVal[0]).intValue() + Integer.parseInt(keyVal[1]));                            
}

但是如果密鑰尚未存在於地圖中,則上面的代碼顯然會拋出異常:

Exception in thread "main" java.lang.NullPointerException

在上面的用例中獲取總數的最佳方法是什么?

您可以獲取給定鍵的值並檢查它是否為空:

for(String dataValue : dataValues){
    String[] keyVal = dataValue.split(":");
    Integer i = totals.get(keyVal[0]);
    if(i == null) {
        totals.put(keyVal[0], Integer.parseInt(keyVal[1]));
    } else {
        totals.put(keyVal[0], i + Integer.parseInt(keyVal[1]));
    }
 }

在上面的用例中獲取總數的最佳方法是什么?

使用Java 8,您可以使用合並功能

for(String dataValue : dataValues){
    String[] keyVal = dataValue.split(":");
    totals.merge(keyVal[0], Integer.parseInt(keyVal[1]), Integer::sum);
}

這個功能有什么作用? 讓我們引用一下這個文檔:

如果指定的鍵尚未與值關聯或與null關聯,則將其與給定的非空值關聯。 否則,將相關值替換為給定重映射函數的結果,或者如果結果為null則刪除

所以當你得到它時,如果沒有與鍵相關的值,你只需用keyVal[1]的int值映射它。 如果已經存在,則需要提供一個函數來決定對兩個值(已映射的值和要映射的值)執行的操作。

在你的情況下你想要求它們,所以這個函數看起來像(a, b) -> a + b ,它可以被方法引用Integer.sum替換,因為它是一個帶兩個int並返回一個int的函數,所以一個有效的候選人(當然還有你需要的語義)。


但是等等,我們實際上可以做得更好! 這是Stream API和收集器類派上用場的地方。

從文件中獲取Stream<String> ,將每一行拆分為一個數組,按每個數組的第一個元素(鍵)對每個數組進行分組,將其第二個元素(值)映射到整數並求它們:

 import static java.util.stream.Collectors.*; ... Map<String, Integer> map = Files.lines(Paths.get("file")) .map(s -> s.split(":")) .collect(groupingBy(arr -> arr[0], summingInt(arr -> Integer.parseInt(arr[1]))); 

另一種方法是使用toMap收集器。

 .collect(toMap(arr -> arr[0], arr -> Integer.parseInt(arr[1]), Integer::sum)); 

從相同的Stream<String[]> ,您可以在一個Map<String, Integer>收集結果,其中鍵是arr[0] ,值是由arr[1]保存的int值。 如果您具有相同的鍵,則通過將它們相加來合並值。

兩者都給出了相同的結果,我喜歡第一個結果,因為使用收集器的名稱,它使得意圖清楚,您正在對元素進行分組,但這取決於您選擇。

一開始可能有點難以理解它,但是一旦你掌握了這些(下游)收集器的概念,它就會非常強大。

希望能幫助到你! :)

由於Java 8而不是map.get您可以使用map.getOrDefault ,如果缺少數據,將返回您定義的默認數據

totals.getOrDefault(keyVal[0], 0).intValue()

這是一個優雅的(編輯:pre Java 8)解決方案:

Integer storedVal = hashMap.get(str);  

String str = keyVal[0];
int num = Integer.parseInt(keyVal[1]);

hashMap.put(str, storedVal == null ? num : storedVal + num);

檢查密鑰是否存在。 如果沒有,請使用hold int創建它。

如果密鑰確實存在,則檢索該值並進行數學運算,存儲總和。

這是有效的,因為如果一個鍵已經存在,'put'將覆蓋該值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM