2015-08-28 5 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 ' m довольно уверен, что 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

код становится простым, если вы считаете, что вы опустили, тх т вам нужна вторая часть разделенной строки, а также:

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); 
     } 
    } 
} 
Смежные вопросы