在Java 8中处理Map<String,List<Object>>列表

4

我正在尝试使用Java 8流API从映射列表中创建一个仅包含键“1”和该列表中不同映射下键“1”的所有值的单个映射。

List<Map<String,Object>> list=new ArrayList<>();
Map<String,Object> map1=new HashMap<>();
map1.put("1", Arrays.asList(new String[] {"A"}));
map1.put("2", Arrays.asList(new String[] {"B"}));

Map<String,Object> map2=new HashMap<>();
map2.put("1", Arrays.asList(new String[] {"C"}));
map2.put("2", Arrays.asList(new String[] {"D"}));

需要的输出: {1=[A,C]}


1
为什么不将list声明为List<Map<String,List<Object>>>?否则,为什么{1=[[A], [C]]}不是预期的输出? - ernest_k
1
@ernest_k 我可以将声明更改为List<Map<String,List<Object>>>,但我需要输出为{1=[A, C]}。 {1 = [A,C]} 将是列表的列表,对吗? - Chirag
@Chirag 对的,这就是你现在的问题不清楚的地方。鉴于当前的代码和 List<Map<String,List<Strinig>>> 作为输入类型,你应该首先问自己的问题是为什么需要这样复杂的数据表示方式,难道没有简化它的方法吗? - Naman
@Naman 需要从一个进程中返回两个列表。因此,我正在维护一个映射,并且该进程可以返回多个映射,这使其成为映射列表。有更好的建议吗? - Chirag
3个回答

5

由于你只有一个条目,因此在这种情况下,你只需要关注值,并且对于键,你可以只使用"1",为此,你可以创建一个如下的地图:

Map<String, List<String>> result = new HashMap<>();
result.put("1", list.stream()
        .filter(e -> e.containsKey("1"))
        .flatMap(e -> e.values().stream())
        .flatMap(List::stream)
        .collect(Collectors.toList()));

或者如评论中Lino所述,您也可以使用:

Map<String, List<String>> result = list.stream()
    .filter(e -> e.containsKey("1"))
    .flatMap(e -> e.values().stream())
    .flatMap(List::stream)
    .collect(Collectors.groupingBy(t -> "1"));

2
如果您不想直接将其放入映射中,可以使用groupingBy收集器而不是toList:.collect(Collectors.groupingBy(i -> "1", i -> i)) - Lino
@LinosaysReinstateMonica,抱歉我不明白你的意思。 - Youcef LAIDANI
抱歉,我的意思是groupingBy(i -> "1"),可以在这里看到。另外,我注意到你的代码不能编译。你的流收集到一个List<List<String>>,我认为你错过了一个flatMap。 - Lino
1
谢谢@LinosaysReinstateMonica,好主意,我把它放在我的答案里 :) - Youcef LAIDANI

4
正如@ernest_k所提到的,您应该将list声明为:List<Map<String,List<String>>> 您可以使用groupingBy收集器:
Map<String, List<String>> result = list.stream()
    .map(m -> m.get("1"))
    .filter(Objects::nonNull)
    .flatMap(Collection::stream)
    .collect(Collectors.groupingBy(t -> "1"));

您可以使用这种方法来消除中间的 filter。但是这可能会更加混乱(而且实际上也是一样的):
Map<String, List<String>> result = list.stream()
    .map(m -> m.get("1"))
    .flatMap(l -> l == null ? Stream.empty() : l.stream())
    .collect(Collectors.groupingBy(t -> "1"));

1
为什么不使用这个 Map<String, List<String>> result = list.stream().filter(m -> m.containsKey("1")) .flatMap(m -> m.get("1").stream()).collect(Collectors.groupingBy(l -> "1")); 呢? - Ravindra Ranwala
@RavindraRanwala 那也可以,但实际上它们的作用是相同的,不是吗?我知道的大多数映射实现都会检查 get(key) != null 是否为 containsKey - Lino

4
你可以做以下操作:
Map<String, List<Object>> result = list.stream()
            .filter(entry -> entry.containsKey("1"))
            .map(entry -> (List<Object>) entry.get("1"))
            .collect(Collectors.toMap(t1 -> "1", 
                          ArrayList::new, (l1, l2) -> { l1.addAll(l2);return l1; }));

或者使用groupingBy收集器:

Map<String, List<Object>> result2 = list.stream()
            .filter(entry -> entry.containsKey("1"))
            .flatMap(entry -> ((List<Object>) entry.get("1")).stream())
            .collect(Collectors.groupingBy(t->"1",Collectors.
                        collectingAndThen(Collectors.toList(),ArrayList::new)));

为什么不使用 groupingBy - Lino

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