2015-08-28 38 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); 
     } 
    } 
}