Java 8嵌套分组

Xua*_*uan 3 java java-8 java-stream

我有2个问题似乎无法解决.第一个是我需要一种方法来进行动态嵌套分组,其中可以有1-n个嵌套组,用户可以传入.

第二个问题是我需要将结果展平,其中键是concat而不是嵌套.

我的示例输入如下所示:

    List<Map<String, String>> fakeData = new LinkedList<>();
    Map<String, String> data1 = new HashMap<>();
    data1.put("ip","10.0.1.0");
    data1.put("uid","root");
    data1.put("group","admin");
    fakeData.add(data1);

    Map<String, String> data2 = new HashMap<>();
    data2.put("ip","10.0.1.1");
    data2.put("uid","tiger");
    data2.put("group","user");
    fakeData.add(data2);

    Map<String, String> data3 = new HashMap<>();
    data3.put("ip","10.0.1.1");
    data3.put("uid","woods");
    data3.put("group","user");
    fakeData.add(data3);
Run Code Online (Sandbox Code Playgroud)

最终结果有一个映射键:

{
  "10.0.1.1user": [
    {
      "uid": "tiger",
      "ip": "10.0.1.1",
      "group": "user"
    },
    {
      "uid": "woods",
      "ip": "10.0.1.1",
      "group": "user"
    }
  ],
  "10.0.1.0admin": [
    "uid": "root",
    "ip": "10.0.1.0",
    "group": "admin"
  ]
}
Run Code Online (Sandbox Code Playgroud)

请注意,键是concat而不是映射中的嵌套映射.

我正在尝试创建一个groupingby,它可以是动态的,没有任何运气:

 fakeData.stream()
                .collect(groupingBy(map -> map.get("ip"),
                        groupingBy(map -> map.get("uuid"),
                                ... nested "n" times)));
Run Code Online (Sandbox Code Playgroud)

这是我试图实现的接口:

public Map<String, List<Map<String, String>>> doGrouping(List<String> columns, 
                                                   List<Map<String, String>> data);
Run Code Online (Sandbox Code Playgroud)

Fed*_*ner 5

请尝试以下方法:

public Map<String, List<Map<String, String>>> doGrouping(
        List<String> columns,
        List<Map<String, String>> data) {

    return data.stream()
        .collect(Collectors.groupingBy(
            elem -> columns.stream()
                .map(elem::get)
                .collect(Collectors.joining())));
}
Run Code Online (Sandbox Code Playgroud)

首先,我流式传输data,这是一个地图列表.我立即使用Collectors.groupingBy为流的每个元素计算的密钥将流收集到列表映射中.

计算密钥是棘手的部分.为此,我流式传输了给定的列表,columns并将这些列中的每一列转换为其对应的流元素值.我通过该Stream.map方法做到了这一点,elem::map作为映射函数传递.最后,我通过使用将这个内部流收集到一个字符串中Collectors.joining,它以有效的方式将流的每个元素连接成一个最终的字符串.

编辑:如果所有元素columns都作为地图元素的键存在,则上面的代码很有效data.为了更安全,请使用以下内容:

return data.stream()
    .collect(Collectors.groupingBy(
        elem -> columns.stream()
            .map(elem::get)
            .filter(Objects::nonNull)
            .collect(Collectors.joining())));
Run Code Online (Sandbox Code Playgroud)

此版本过滤掉null流中的元素,如果某些map元素不包含columns列表中指定的键,则可能会出现这些元素.

  • 你也可以使用`c - > elem.getOrDefault(c,"")`. (2认同)