2015-08-28 87 views
5

我有以下格式的一系列輸入字符串:的Java 8 groupingby自定義鍵

typeA:code1, 
typeA:code2, 
typeA:code3, 
typeB:code4, 
typeB:code5, 
typeB:code6, 
typeC:code7, 
... 

,我需要得到Map<String, List<String>>結構如下:

typeA, [code1, code2, code3] 
typeB, [code4, code5, code6] 
typeC, [code7, code8, ...] 

美中不足的是爲了生成每種類型,我需要在每個輸入字符串上調用像這樣的函數:

public static String getType(String code) 
{ 
    return code.split(":")[0]; // yes this is horrible code, it's just for the example, honestly 
} 

I'我非常相信Streams和Collectors可以做到這一點,但我正在努力使正確的咒語成爲可能。

回答

8

下面是做這件事(假定類被命名爲A):

Map<String, List<String>> result = Stream.of(input) 
          .collect(groupingBy(A::getType, mapping(A::getValue, toList()))); 

如果你想輸出進行排序,你可以使用一個TreeMap,而不是默認的HashMap:

.collect(groupingBy(A::getType, TreeMap::new, mapping(A::getValue, toList()))); 

完整的例子:

public static void main(String[] args) { 
    String input[] = ("typeA:code1," + 
       "typeA:code2," + 
       "typeA:code3," + 
       "typeB:code4," + 
       "typeB:code5," + 
       "typeB:code6," + 
       "typeC:code7").split(","); 

    Map<String, List<String>> result = Stream.of(input) 
        .collect(groupingBy(A::getType, mapping(A::getValue, toList()))); 
    System.out.println(result); 
} 

public static String getType(String code) { 
    return code.split(":")[0]; 
} 
public static String getValue(String code) { 
    return code.split(":")[1]; 
} 
+0

謝謝,這是非常接近我想出來的。我意識到groupingBy中第一個參數的類型是一個func,我可以在那裏使用我的getType函數。 – endian

6

如果你考慮你已經省略,你的代碼變得簡單T優需要分割字符串的第二部分,以及:

Map<String, List<String>> result = Stream.of(input).map(s->s.split(":", 2)) 
    .collect(groupingBy(a->a[0], mapping(a->a[1], toList()))); 

(假設你有一個import static java.util.stream.Collectors.*;

沒有什麼錯拆分String到一個數組中,實現了即使是「快-path「用於使用單個簡單字符而不是複雜的正則表達式進行分割的常見情況。

+0

謝謝,這也是一個好方法。 – endian

2

雖然我太慢了,但這是MCVE顯示如何用Collectors#groupingBy解決這個問題。

定義「分類器」和「映射器」顯然有不同的選項。在這裏,我只是使用String#substring來找到":"之前和之後的部分。

import static java.util.stream.Collectors.groupingBy; 
import static java.util.stream.Collectors.mapping; 
import static java.util.stream.Collectors.toList; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 

public class GroupingBySubstringsTest 
{ 
    public static void main(String[] args) 
    { 
     List<String> strings = new ArrayList<String>(); 
     strings.add("typeA:code1"); 
     strings.add("typeA:code2"); 
     strings.add("typeA:code3"); 
     strings.add("typeB:code4"); 
     strings.add("typeB:code5"); 
     strings.add("typeB:code6"); 
     strings.add("typeC:code7"); 

     Map<String, List<String>> result = strings.stream().collect(
      groupingBy(s -> s.substring(0, s.indexOf(":")), 
       mapping(s -> s.substring(s.indexOf(":")+1), toList()))); 

     for (Entry<String, List<String>> entry : result.entrySet()) 
     { 
      System.out.println(entry); 
     } 
    } 
}