Java 8嵌套分组

时间:2017-05-05 04:57:51

标签: java java-8 java-stream

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

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

我的示例输入如下所示:

    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);

最终结果有一系列地图键:

{
  "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"
  ]
}

请注意,键是连贯的,而不是映射中的嵌套映射。

我正在尝试创建一个可以动态而没有运气的分组:

 fakeData.stream()
                .collect(groupingBy(map -> map.get("ip"),
                        groupingBy(map -> map.get("uuid"),
                                ... nested "n" times)));

这是我正在尝试实现的界面:

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

2 个答案:

答案 0 :(得分: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())));
}

首先,我流式传输了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())));

此版本过滤掉流中的null个元素,如果某个地图元素不包含columns列表中指定的密钥,则可能会出现这种情况。

答案 1 :(得分:1)

不确定使用流,但如果您更喜欢普通的java方式,那就容易多了。 如果我正确理解你的问题,那么你想要构建的方法。您可能需要进行一些调整以使其更快。

if(foo != null)
{
   bar = foo.buz();
}

测试:

public Map<String, List<Map<String, String>>> doGrouping(List<String> columns, List<Map<String, String>> data) {
    Map<String, List<Map<String, String>>> output = new HashMap<>();
    for (Map<String, String> map : data) {
        String key = "";
        for(String column :  columns) key += "".equals(key) ? (map.get(column)) : (":" + map.get(column));
        output.computeIfAbsent(key, k -> Arrays.asList(map));
    }
    return output;
}