将地图列表合并到一个地图中

时间:2017-07-18 17:19:44

标签: java list dictionary java-stream

我正在尝试将Map列表合并为一个:

List<Map<String, List<Long>>> dataSet;
Map<String, Set<Long>> uniqueSets = dataset.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collector.of(
            HashSet<Long>::new,
            ...,
            ...
        )
    ));

这个想法是uniqueSet应该在每个集合中保存一个唯一ID(Longs)列表(由String标识)。但我不确定...部分。

至于请求的示例(在JSON中):

输入:

[
    {
        "Collection1": [1, 2, 3, 3],
        "Collection2": [2, 3]
    },
    {
        "Collection1": [3, 4],
        "Collection3": [1, 2]
    }
]

输出:

{
    "Collection1": [1, 2, 3, 4],
    "Collection2": [2, 3],
    "Collection3": [1, 2]
}

5 个答案:

答案 0 :(得分:2)

如果我理解了你的问题,如果给出这两张地图:

<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
    <head>
        <title>Shopping</title>
        <script type="text/javascript" src="JavaScript.js"></script>
    </head>
    <body>
        <div id="results"></div>
        <button type="button" id="addButton">Add one item</button>
        <button type="button" id="removeButton">Remove one item</button>
    </body>
</html>

你想要像这样组合它们:

{Mike=[5, 6], Jack=[1, 2, 3]}
{Fred=[7, 8], Jack=[4, 5]}

你走了:

{Mike=[5, 6], Fred=[7, 8], Jack=[1, 2, 3, 4, 5]}

那是:

  • 您的供应商是正确的:创建新的Map<String, List<Long>> uniqueSets = dataset.stream() .flatMap(m -> m.entrySet().stream()) .collect(Collectors.groupingBy( Map.Entry::getKey, Collector.of( ArrayList<Long>::new, (list, item) -> list.addAll(item.getValue()), (left, right) -> { left.addAll(right); return left; }) )); 以累积值
  • 第二部分是累加器:收集容器(列表)和项目的东西,并将项目添加到容器中。请注意,这些项目是ArrayList个实例。
  • 最后一块是组合器,将由累加器填充的两个容器合并为一个

答案 1 :(得分:1)

你可以使用这样的东西

    Map<String, List<Long>> uniqueSets = dataset.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.groupingBy(
                    Map.Entry::getKey,
                    Collector.of(
                            ArrayList<Long>::new,
                            (x, y) -> { x.addAll(y.getValue()); },
                            (x, y) -> {
                                List<Long> r = new ArrayList<>(x);
                                r.addAll(y);
                                return r;
                            }
                    )
            ));

修改

其他方法是

    Map<String, List<Long>> uniqueSets = dataset.stream()
            .flatMap(m -> m.entrySet().stream())
            .flatMap(e -> e.getValue().stream().map(v -> new Pair(e.getKey(), v)))
            .collect(Collectors.groupingBy(
                    Pair::getKey,
                    Collectors.mapping(
                            Pair::getValue,
                            Collectors.toList()
                    ))
            );

但它需要配对类(你可以在许多库中找到类似的类)

class Pair {
    final String key;
    final Long value;

    public Pair(String key, Long value) {
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public Long getValue() {
        return value;
    }
}

答案 2 :(得分:0)

这样的事情怎么样:

Map<String, Set<Long>> uniqueSets = new HashMap<>();
dataset.forEach(map -> map.forEach((string, list) -> {
    if (uniqueSets.get(string) != null){
        list.forEach(id -> uniqueSets.get(string).add(id));
    }else{
        uniqueSets.put(string, new HashSet<>(list));
    }
}));

答案 3 :(得分:0)

试试这个。

Map<String, List<Long>> r =
    dataSet.stream()
    .flatMap(e -> e.entrySet().stream())
    .flatMap(e -> e.getValue().stream()
        .map(v -> new AbstractMap.SimpleEntry<String, Long>(e.getKey(), v)))
    .distinct()
    .collect(Collectors.groupingBy(
        Entry::getKey,
        Collectors.mapping(Entry::getValue, Collectors.toList())));
System.out.println(dataSet);
System.out.println(r);

结果:

[{Collection1=[1, 2, 3, 3], Collection2=[2, 3]}, {Collection1=[3, 4], Collection3=[1, 2]}]
{Collection1=[1, 2, 3, 4], Collection3=[1, 2], Collection2=[2, 3]}

答案 4 :(得分:0)

正如您特别要求使用自定义收集器的基于流的解决方案,这是一种方式:

List<Map<String, List<Long>>> dataSet;
Map<String, Set<Long>> uniqueSets = dataset.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collector.of(
            HashSet<Long>::new,
            (set, e) -> set.addAll(e.getValue()),
            (left, right) -> { left.addAll(right); return left; })));

但是,我认为没有流可以提供更好的解决方案:

Map<String, Set<Long>> uniqueSets = new HashMap<>();

dataSet.forEach(map -> 
    map.forEach((k, v) -> uniqueSets.merge(
        k, 
        new HashSet<>(v), 
        (o, n) -> { o.addAll(n); return o; })));

迭代遍历映射列表,并且对于每个映射,它迭代其条目,以便对于每个映射的每个键/值对,将值转换为映射到其的HashSetuniqueSets地图中的关键字。这是通过Map.merge方法实现的,如果条目中不存在该条目,则创建条目,或者如果已存在该值的键,则将新值与旧值合并。对于此合并,我使用的是Set.addAll