将展平对象列表分组为复杂的嵌套结构

Grouping a list of Flattened Objects into a complex Nested structure

我有一个 List 个对象 A,其中对象 A 具有以下形式:

class A {
    private String a1;
    private String a2;
    private String a3;
    private String a4;
    private String a5;
    private String a6;
}

我需要先按 a1a2 对列表进行分组,然后按 a3a4 分组,结果为 List<B>

对象B具有这种形式

class B {
    private String a1; 
    private String a2;
    private List<C> list;
}

并且对象 C 具有这种形式

class C {
    private String a3;
    private String a4;
    private List<D> list;
}

并且对象 D 具有这种形式

class D {
    private String a5;
    private String a6;
}

示例。给定列表:

  [{a1="100", a2="bbb", a3="100100", a4="ddd", a5="1", a6="10"},
   {a1="100", a2="bbb", a3="100100", a4="ddd", a5="2", a6="20"},
   {a1="100", a2="bbb", a3="100200", a4="eee", a5="3", a6="30"},
   {a1="200", a2="ccc", a3="200100", a4="fff", a5="4", a6="40"},
   {a1="200", a2="ccc", a3="200200", a4="ggg", a5="5", a6="50"},
   {a1="200", a2="ccc", a3="200300", a4="hhh", a5="6", a6="60"}]

我需要这个结构作为结果:

    {"B": [
    {
      "a1": "100",
      "a2": "bbb",
      "C": [
        {
          "a3": "100100",
          "a4": "ddd",
          "D": [
            {"a5": "1", "a6": "10"},
            {"a5": "2", "a6": "20"}
          ]
        },
        {
          "a3": "100200",
          "a4": "eee",
          "D": [
            {"a5": "3", "a6": "30"}
          ]
        }
      ]
    },
     {
      "a1": "200",
      "a2": "ccc",
      "C": [
        {
          "a3": "200100",
          "a4": "fff",
          "D": [
            {"a5": "4", "a6": "40"}
          ]
        },
        {
          "a3": "200200",
          "a4": "ggg",
          "D": [
            {"a5": "5", "a6": "50"}
          ]
        },
        {
          "a3": "200300",
          "a4": "hhh",
          "D": [
            {"a5": "6", "a6": "60"}
          ]
        }
      ]
    }
  ]
}

Java11 中的流是否可能?也欢迎任何其他实现此目标的方法。

下面提供的代码可以满足要求。

由于您的数据结构方式存在问题:

  • 如果字符串对 a1a2a3a4 等数据块构成 self-contained 个信息单元在你的域模型中有一个特殊的含义,你不应该创建像 A 这样的带有大量字符串字段的野兽(object A 必须包含一个对象集合 B 并且它)。 设计有问题,你应该好好改进一下类.
  • 您的示例中的某些字符串包含数字数据。如果您稍后在某个地方解析它,那也不好。它们必须替换为数字数据类型。

下面的解决方案使用了 built-in 收集器 Collector.collectionAndThen()Collectors.groupingBy()Map.EntrygroupingBy() 收集器 中用作数据的中间容器(Map.Entry 对象是 在两个地图中)。

函数负责将这些映射转换为列表List<C>List<B>.

public static void main(String[] args) {
    List<A> aList = List.of(new A("100", "bbb", "100100", "ddd", "1", "10"),
                            new A("100", "bbb", "100100", "ddd", "2", "20"),
                            new A("100", "bbb", "100200", "eee", "3", "30"),
                            new A("200", "ccc", "200100", "fff", "4", "40"),
                            new A("200", "ccc", "200200", "ggg", "5", "50"),
                            new A("200", "ccc", "200300", "hhh", "6", "60"));
    
    Function<Map<Map.Entry<String, String>, List<D>>, List<C>> mapToListC =
        mapC ->  mapC.entrySet().stream()
                .map(entry -> new C(entry.getKey().getKey(),
                                    entry.getKey().getValue(),
                                    entry.getValue()))
                .collect(Collectors.toList());

    Function<Map<Map.Entry<String, String>, Map<Map.Entry<String, String>, List<D>>>, List<B>> mapToListB =
        mapB ->  mapB.entrySet().stream()
            .map(entry -> new B(entry.getKey().getKey(),
                                entry.getKey().getValue(),
                                mapToListC.apply(entry.getValue())))
            .collect(Collectors.toList());

    List<B> bList = aList.stream()
        .collect(Collectors.collectingAndThen(
                Collectors.groupingBy((A a) -> Map.entry(a.getA1(), a.getA2()),
                    Collectors.groupingBy((A a) -> Map.entry(a.getA3(), a.getA4()),
                        Collectors.mapping((A a) -> new D(a.getA5(), a.getA6()),
                            Collectors.toList()))),
                mapToListB));
    
    bList.forEach(System.out::println);
}

输出

B{a1='200', a2='ccc'list=
    C{a3='200300', a4='hhh'list=
        D{a5='6', a6='60'}}
    C{a3='200100', a4='fff'list=
        D{a5='4', a6='40'}}
    C{a3='200200', a4='ggg'list=
        D{a5='5', a6='50'}}}
B{a1='100', a2='bbb'list=
    C{a3='100200', a4='eee'list=
        D{a5='3', a6='30'}}
    C{a3='100100', a4='ddd'list=
        D{a5='1', a6='10'}
        D{a5='2', a6='20'}}}