Java8 streams : Transpose map with values as list

前端 未结 4 2111
情歌与酒
情歌与酒 2020-12-03 08:45

I have map with key as String and value as List. List can have 10 unique values. I need to convert this map with key as Integer and value as List. Example as below :

相关标签:
4条回答
  • 2020-12-03 09:19

    It's a bit scary (I generally try to break it down to make it more readable) but you could do it this way:

    Map<Integer, List<String>> transposeMap = new HashMap<>();
    
    map.forEach((key, list) -> list.stream().forEach(
        elm -> transposeMap.put(elm,
            transposeMap.get(elm) == null ? Arrays.asList(key) : (Stream.concat(transposeMap.get(elm).stream(),
                Arrays.asList(key).stream()).collect(Collectors.toList())))));
    

    Assuming Map<String, List<Integer>> map is your original Map that you want to transpose. transposeMap will have transposed map that you need.

    0 讨论(0)
  • 2020-12-03 09:19

    You can Achieve in this way

    Let suppose I have Person class with Gender and Age . I want to get it in this form

    Map<SEX,List<Person>> 
    

    I would write simply

    Map<SEX,List<Person>> map =  personList.stream()
    
                               .collect(Collectors.groupingBy(Person::getGender));
    

    it will get me something like below (one key against multiple values )

    key:MALE
    age31sexMALE
    age28sexMALE
    
    key:FEMALE
    age40sexFEMALE
    age44sexFEMALE
    
    0 讨论(0)
  • An idea could be to generate all value-key pairs from the original map and then group the keys by these values:

    import java.util.AbstractMap.SimpleEntry;
    
    import static java.util.stream.Collectors.groupingBy;
    import static java.util.stream.Collectors.mapping;
    import static java.util.stream.Collectors.toList;
    
    ...
    
    Map<Integer, List<String>> transposeMap =
        map.entrySet()
           .stream()
           .flatMap(e -> e.getValue().stream().map(i -> new SimpleEntry<>(i, e.getKey())))
           .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
    
    0 讨论(0)
  • 2020-12-03 09:45

    Alexis’ answer contains the general solution for this kind of task, using flatMap and a temporary holder for the combination of key and flattened value. The only alternative avoiding the creation of the temporary holder objects, is to re-implement the logic of the groupingBy collector and inserting the loop over the value list logic into the accumulator function:

    Map<Integer, List<String>> mapT = map.entrySet().stream().collect(
        HashMap::new,
        (m,e) -> e.getValue().forEach(
                     i -> m.computeIfAbsent(i,x -> new ArrayList<>()).add(e.getKey())),
        (m1,m2) -> m2.forEach((k,v) -> m1.merge(k, v, (l1,l2)->{l1.addAll(l2); return l1;})));
    
    0 讨论(0)
提交回复
热议问题