Search code examples
javajava-8java-streamcollectors

Java 8 groupingby with custom key


I have a series of input Strings in the following format:

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

and I need to get a Map<String, List<String>> with the following structure:

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

The catch is that to generate each type I need to call a function like this one on each input String:

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

I'm pretty confident that Streams and Collectors can do this, but I'm struggling to get the right incantation of spells to make it happen.


Solution

  • Here is one way to do it (assuming the class is named A):

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

    If you want the output sorted you can use a TreeMap instead of the default HashMap:

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

    Full example:

    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];
    }