Java流改变列表中映射的键

3

可以使用Java Stream来更改列表中地图的键吗? 即,给定地图的原始列表是:

List<Map<String, String>> list = new ArrayList<Map<String, String>>() {{
            add(new HashMap<String, String>() {{
                put("id", "1");
                put("display", "foo");
            }});
            add(new HashMap<String, String>() {{
                put("id", "2");
                put("display", "bar");
            }});
        }};

        System.out.println(list.toString());

从上面的列表中(演示输出)

[{display=foo, id=1}, {display=bar, id=2}]

转换为一个map列表:

[{sample=foo, sample_id=1}, {sample=bar, sample_id=2}]

基本上,将键“id”更改为“sample_id”,将“display”更改为“sample”。

看起来您在使用地图时编写自己的类可能更好。例如,如果列表中的所有地图都有2个键(id和display),为什么不编写一个带有两个字段(id和display)的类呢?此外,请勿使用{{...}}初始化列表和映射。 - cpp beginner
尽管使用这样的“List”、“Map”组合是违反良好实践的,但有趣的是,通过流操作重命名键(删除并重新插入)是否可能。我怀疑那里会发生CME的风险很高,不过还是值得一试。 - Naman
有什么理由避免使用 {{ ... }} 来处理列表/映射吗? - TX T
找到了避免使用{{}}的原因答案。 - TX T
4个回答

7

这将有效运作,

    List<Map<String, String>> list2 = list.stream().map(e -> {
        Map<String, String> map = new HashMap<>();
        for (Map.Entry x : e.entrySet()) {
            if (x.getKey().equals("id")) {
                map.put("sample_id", (String) x.getValue());
            } else if (x.getKey().equals("display")) {
                map.put("sample", (String) x.getValue());
            } else {
                map.put((String) x.getKey(), (String) x.getValue());
            }
        }

        return map;
    }).collect(Collectors.toList());

略微更加优雅,
    List<Map<String, String>> list3 = list.stream().map(
            e -> e.entrySet().stream().collect(Collectors.toMap(
                    x -> {
                        if (x.getKey().equals("id")) {
                            return "sample_id";
                        } else if (x.getKey().equals("display")) {
                            return "sample";
                        } else {
                            return x.getKey();
                        }
                    },
                    Map.Entry::getValue))).collect(Collectors.toList());

3
最直接的方法是遍历List并将每个HashMap映射到翻译后的HashMap
list.stream()
    .map(this::translate)
    .collect(Collectors.toList());

翻译后的 HashMap 是这个 Map 的副本,其中每个键都被翻译:

 private Map<String, String> translate(Map<String, String> map) {
        HashMap<String, String> translatedMap = new HashMap<>(map);
        translate(translatedMap, "id", "sample_id");
        translate(translatedMap, "display", "sample");
        return translatedMap;
 }

由于我们正在处理流数据,因此重要的是要复制原始映射,以避免处理共享可变状态。然后,我们通过获取键的值、输入新键的值并删除旧值来翻译我们的新映射中的每个键:

private Map<String, String> translate(Map<String, String> map, String originalKey, String newKey) {
    map.put(newKey, map.remove(originalKey));
    return map;
}

然后输出如下:
[{display=foo, id=1}, {display=bar, id=2}]
[{sample=foo, sample_id=1}, {sample=bar, sample_id=2}]

0
如果您希望原始地图保持不变,请遵循Nick Vanderhoven的方法。但是,如果您可以更改输入地图,则可以缩短它甚至无需流式传输:
list.forEach(map -> {
    map.put("sample", map.remove("display"));
    map.put("sample_id", map.remove("id"));
});

如果你想要的话,当然可以使用流(但仍需更改原始映射!):

list.stream()
    .peek(map -> {
        map.put("sample", map.remove("display"));
        map.put("sample_id", map.remove("id"));
    })
    .collect(Collectors.toList());

-2

其实有一个方法可以遵循。

您可以重写 .toString() 方法并赋予它自己的实现方式。这样,您可以以任何所需的方式显示它。


1
我认为OP想要更多的不仅仅是显示地图条目的变化,他们希望实际的键也能改变。 - dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接