Java8如何使用流和lambda将三级嵌套列表转换为嵌套HashMap

时间:2019-10-04 05:08:40

标签: java lambda java-8 hashmap java-stream

我正在尝试将3级嵌套列表转换为Nested HashMap。

同一函数的声明为:

Map<Key1, Map<Key2, List<String>>> transformToMap (List<Obj1> inputList)

inputList内部具有嵌套列表,而该列表又具有嵌套列表。

我编写的代码使用传统的for循环,如下所示:

private Map<Key1 , Map<Key2, List<String>>> reverseLookup(List<Key2> key2List){
    Map<Key1 , Map<Key2, List<String>>>  resultMap = new HashMap<>();
    key2List.forEach(key2->{
        List<ElementObject> elementObjects = key2.getElementObjects();
        elementObjects.forEach(elementObject->{
            final String name = elementObject.getName();
            elementObject.getApplicablePeriods().forEach(applicablePeriod-> {
                Key1 key1 = applicablePeriod.getKey1();
                Map<Key2, List<String>> map2 = resultMap.get(key1);
                if(map2 == null){
                    map2 = new HashMap<>();
                }
                List<String> stringList = map2.get(key2);
                if(stringList == null){
                    stringList = new ArrayList<>();
                }
                stringList.add(name);
                map2.put(key2, stringList);
                resultMap.put(key1, map2);
            });
        });
    });

    return resultMap;
}

相同的类结构如下:

class Key2{

    List<ElementObject> elementObjects;

    //getters & setters
}

class ElementObject {
    String name;
    //few more params
    List<ApplicablePeriod> applicablePeriods;
     //getters & setters
}

class ApplicablePeriod{
    Key1 key1;
    //getters & setters
}

class Key1{
    //some parameters
    //getters & setters
}

上面的代码符合我的期望。

使用Collectors.toMap将其转换为流lambda的有效方法是什么?

我尝试了以下操作:

inputList
        .stream()
        .flatMap(item -> item.getObj2List().stream())
        .flatMap(nestedItem -> nestedItem.getKeyList().stream())
        .collect(Collectors.toMap(a-> a.get()))

但没有得到Collectors.toMap中下一步应该做什么。 无法处理仅在第3个for循环之前使用的final String name = nestedItem.getName();

让我知道解决此问题的方法。

2 个答案:

答案 0 :(得分:0)

我没有任何测试数据来查看它是否创建了与您的传统代码类似的东西。但是看看这个,如果有帮助,请告诉我:

key2List.stream().flatMap((key2) -> key2.elementObjects.stream().map((element) -> new AbstractMap.SimpleImmutableEntry<>(key2, element)))
    .flatMap((entry) -> entry.getValue().applicablePeriods.stream().map((period) -> new AbstractMap.SimpleImmutableEntry<>(period.key1, new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), entry.getValue().name))))
    .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())))));

答案 1 :(得分:0)

事实上,问题是你想访问同一个 Stream 内的多个抽象级别,这通常是不可能的,除非你有

  • 嵌套流
  • 一个可以保存对更高对象的引用的对象

我以第二种方式修复它。

我正在使用 和以下功能

  • Collectors#mapMulti
  • Collectors#groupingBy
  • 本地定义的 record
private Map<Key1, Map<Key2, List<String>>> reverseLookup(List<Key2> key2List) {
    record HolderObject(Key2 key2, ElementObject elementObject, ApplicablePeriod applicablePeriod){}

    return key2List.stream()
            .mapMulti((Key2 key2, Consumer<HolderObject> consumer) -> {
                List<ElementObject> elementObjects = key2.getElementObjects();
                elementObjects.forEach(elementObject ->
                        elementObject.getApplicablePeriods().forEach(applicablePeriod -> {
                            consumer.accept(new HolderObject(
                                    key2,
                                    elementObject,
                                    applicablePeriod
                            ));
                        })
                );
            })
            .collect(Collectors.groupingBy(
                    h -> h.applicablePeriod().getKey1(),
                    Collectors.groupingBy(
                            HolderObject::key2,
                            Collectors.mapping(
                                    h -> h.elementObject().getName(),
                                    Collectors.toList()
                            )
                    )
            ));
}

这是一个兼容的解决方案

private Map<Key1, Map<Key2, List<String>>> reverseLookup(List<Key2> key2List) {
    return key2List
            .stream()
            .flatMap(key2 -> key2.getElementObjects()
                    .stream()
                    .flatMap(elementObject -> elementObject.getApplicablePeriods()
                            .stream()
                            .map(applicablePeriod -> new HolderObject(
                                    key2,
                                    elementObject,
                                    applicablePeriod
                            ))))
            .collect(Collectors.groupingBy(
                    h -> h.getApplicablePeriod().getKey1(),
                    Collectors.groupingBy(
                            HolderObject::getKey2,
                            Collectors.mapping(
                                    h -> h.getElementObject().getName(),
                                    Collectors.toList()
                            )
                    )
            ));
}

@Value
public static class HolderObject {
    Key2 key2;
    ElementObject elementObject;
    ApplicablePeriod applicablePeriod;
}