简体   繁体   English

使用Java Stream API将类型X转换为Map <K,Map <V,X >>中的Y.

[英]Convert type X to Y in Map<K, Map<V, X>> using Java Stream API

I want to convert inner map from map of maps. 我想从地图地图转换内部地图。

Old map: Map<String, Map<LocalDate, Integer>> Integer means seconds 旧地图: Map<String, Map<LocalDate, Integer>>整数表示秒

New map: Map<String, Map<LocalDate, Duration>> 新地图: Map<String, Map<LocalDate, Duration>>

I have tried created new inner map, but got an error 我试过创建了新的内部地图,但是出了错误

Error: java: no suitable method found for putAll(java.util.stream.Stream<java.lang.Object>) method java.util.Map.putAll(java.util.Map<? extends java.time.LocalDate,? extends java.time.Duration>) is not applicable 错误:java:找不到适合putAll(java.util.stream.Stream<java.lang.Object>)方法putAll(java.util.stream.Stream<java.lang.Object>)方法java.util.Map.putAll(java.util.Map<? extends java.time.LocalDate,? extends java.time.Duration>)不适用

oldMap.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey,
                e -> new HashMap<LocalDate, Duration>() {{
                    putAll(
                        e.getValue().entrySet().stream()
                            .map(x -> new HashMap.SimpleEntry<LocalDate, Duration>
                                (x.getKey(), Duration.ofSeconds(x.getValue())))
                    );
                }}
            ));

If you want compact code, you may use 如果你想要紧凑的代码,你可以使用

Map<String, Map<LocalDate, Duration>> newMap = new HashMap<>();
oldMap.forEach((s,o) -> o.forEach((d, i) ->
    newMap.computeIfAbsent(s, x->new HashMap<>()).put(d, Duration.ofSeconds(i))));

If you want to avoid unnecessary hash operations, you may expand it a bit 如果要避免不必要的哈希操作,可以稍微扩展一下

Map<String, Map<LocalDate, Duration>> newMap = new HashMap<>();
oldMap.forEach((s,o) -> {
    Map<LocalDate, Duration> n = new HashMap<>();
    newMap.put(s, n);
    o.forEach((d, i) -> n.put(d, Duration.ofSeconds(i)));
});

Quick and clean 快速而干净

HashMap<String, HashMap<LocalDate, Duration>> newMap = new HashMap<>();
oldHashMap.forEach((key, innerMap) -> {
    HashMap<LocalDate, Duration> newStuff = new HashMap<>();
    innerMap.forEach((k2,v2) -> newStuff.put(k2,Duration.ofSeconds(v2)));
    newMap.put(key, newStuff);
});

And one more... 还有一个......

 Map<String, Map<LocalDate, Duration>> newMap = map.entrySet().stream().collect(
            Collectors.toMap(Entry::getKey,
                    entry -> entry.getValue().entrySet().stream().collect(
                            Collectors.toMap(Entry::getKey, e -> Duration.ofSeconds(e.getValue())))));

My two cents, create a method to transform Map<K, V1> to a Map<K, V2> : 我的两分钱,创建一个方法将Map<K, V1>转换为Map<K, V2>

public static <K,V1,V2> Map<K, V2> transformValues(final Map<K, V1> input, final Function<V1,V2> transform) {
    Function<Map.Entry<K, V1>, V2> mapper = transform.compose(Map.Entry::getValue);
    return input.entrySet().stream()
            .collect(toMap(Map.Entry::getKey, mapper));
}

Then your code becomes: 然后你的代码变成:

Map<String, Map<LocalDate, Duration>> transformed 
    = transformValues(maps, map -> transformValues(map, Duration::ofSeconds));

Let's extract a helper method toMap to makes the problem more simpler. 让我们提取一个辅助方法toMap来使问题更简单。

Map<String, Map<LocalDate, Duration>> result = oldMap.entrySet().stream()
    .map(entry -> new AbstractMap.SimpleEntry<>(
         entry.getKey(),
         entry.getValue().entrySet().stream()
                         .collect(toMap(it -> Duration.ofSeconds(it.longValue())))
//                                ^--- mapping Integer to Duration
    )).collect(toMap(Function.identity()));



<K, V, R> Collector<Map.Entry<K, V>, ?, Map<K, R>> toMap(Function<V, R> mapping) {
    return Collectors.toMap(
         Map.Entry::getKey,
         mapping.compose(Map.Entry::getValue)
    );
}

AND you can simplified the code as further since the primary logic is duplicated: adapts a value to another value in a Map . 并且您可以进一步简化代码,因为主逻辑是重复的: 将值调整为Map另一个值

Function<
    Map<String, Map<LocalDate, Integer>>,
    Map<String, Map<LocalDate, Duration>>
> mapping = mapping(mapping(seconds -> Duration.ofSeconds(seconds.longValue())));
//          |       |
//          |   adapts Map<LocalDate, Integer> to Map<LocalDate,Duration>
//          | 
//adapts Map<String,Map<LocalDate,Integer>> to Map<String,Map<LocalDate,Duration>>

Map<String, Map<LocalDate, Duration>> result = mapping.apply(oldMap);


<K, V1, V2> Function<Map<K, V1>, Map<K, V2>> mapping(Function<V1, V2> mapping) {
    return it -> it.entrySet().stream().collect(toMap(mapping));
}

THEN you can use it anywhere that needs a Function<Map<?,?>,Map<?,?>> to adapts the value to another value,for example: 那么你可以在任何需要Function<Map<?,?>,Map<?,?>>地方使用它来将值调整为另一个值,例如:

Map<String, Map<LocalDate, Duration>> result = Optional.of(oldMap)
        .map(mapping(mapping(seconds -> Duration.ofSeconds(seconds.longValue()))))
        .get();

I would prefer to iterate over the entries of your old map and streaming over the inner map: 我更喜欢迭代旧地图的条目并在内部地图上流式传输:

for (Entry<String, Map<LocalDate, Integer>> entry : oldMap.entrySet()) {
    Map<LocalDate, Duration> asDuration = entry.getValue().entrySet().stream()
        .collect(Collectors.toMap(e -> e.getKey(), e -> Duration.ofSeconds(e.getValue().longValue())));
    newMap.put(entry.getKey(), asDuration);
}

Otherwise you need a second stream inside your collect : 否则,您需要在collect使用第二个流:

newMap = oldMap.entrySet().stream()
        .collect(Collectors.toMap(s -> s.getKey(), s -> s.getValue().entrySet().stream()
        .collect(Collectors.toMap(e -> e.getKey(), e -> Duration.ofSeconds(e.getValue().longValue())))));

If i understand you correct,you can see following code: 如果我理解你的错误,你可以看到以下代码:

oldMap.entrySet().stream()
            .collect(Collectors.toMap(x -> x.getKey(),
                    x -> {
                        Map<LocalDate, Duration> temp = new HashMap<>();
                        x.getValue().forEach((k, v) -> {
                            temp.put(k, Duration.ofSeconds(v));
                        });
                        return temp;
                    })

            );

For completeness, here's a version that uses Guava's Maps.transformValues : 为了完整Maps.transformValues ,这是一个使用Guava的Maps.transformValues的版本:

Map<String, Map<LocalDate, Duration>> result = 
    Maps.transformValues(oldMap, m -> Maps.transformValues(m, Duration::ofSeconds));

Here is solution by StreamEx : 以下是StreamEx的解决方案:

EntryStream.of(oldMap)
           .mapValues(v -> EntryStream.of(v).mapValues(Duration::ofSeconds).toMap())
           .toMap();

如何转换列表<object>至 Map<k, v> 使用 java stream<div id="text_translate"><p> 我想将List&lt;ObjectInList&gt;转换为Map&lt;K, V&gt;</p><pre> class ObjectInList { List&lt;Long&gt; listWithLong; Map&lt;String, Object&gt; dataMap; // there is 'id' key, and i want to use this id as key in map to be converted }</pre><p> 新的 map 格式如下</p><pre>String type; // this type is value of dataMap. List&lt;Long&gt; contents</pre><p> List&lt;Object&gt;中的每个 Object 都可以有重复的类型</p><p>例如</p><pre>///////// before converted //////////// [ { list: [1,2,3], dataMap: { type: "a", } }, { list: [4,5,6], dataMap: { type: "b", } }, { list: [7,8], dataMap: { type: "a", } }, ] ///////////// after converted ////////// { "a": [1,2,3,7,8], "b": [4,5,6] }</pre></div></k,></object> - How to convert LIst<Object> to Map<K, V> with using java stream

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何转换地图<X, Map<Y,Z> &gt; 到地图<Y, Map<X,Z> &gt; 使用 Java8 流 - How to convert Map<X, Map<Y,Z>> to Map<Y, Map<X,Z>> using Java8 stream Java8:如何转换地图 <X, List<Y> &gt;到地图 <Y,X> 使用Stream? - Java8: How to Convert Map<X, List<Y>> to Map<Y,X> using Stream? 如何转换列表<object>至 Map<k, v> 使用 java stream<div id="text_translate"><p> 我想将List&lt;ObjectInList&gt;转换为Map&lt;K, V&gt;</p><pre> class ObjectInList { List&lt;Long&gt; listWithLong; Map&lt;String, Object&gt; dataMap; // there is 'id' key, and i want to use this id as key in map to be converted }</pre><p> 新的 map 格式如下</p><pre>String type; // this type is value of dataMap. List&lt;Long&gt; contents</pre><p> List&lt;Object&gt;中的每个 Object 都可以有重复的类型</p><p>例如</p><pre>///////// before converted //////////// [ { list: [1,2,3], dataMap: { type: "a", } }, { list: [4,5,6], dataMap: { type: "b", } }, { list: [7,8], dataMap: { type: "a", } }, ] ///////////// after converted ////////// { "a": [1,2,3,7,8], "b": [4,5,6] }</pre></div></k,></object> - How to convert LIst<Object> to Map<K, V> with using java stream 转换清单 <V> 在地图上 <K,V> 与流Java 8 - Convert List<V> in Map<K,V> with stream Java 8 Java8:地图 <X, Y> 到地图 <X, Z> 使用RxJava - Java8: Map<X, Y> to Map<X, Z> using RxJava java8将Map <X,Y> + Map <Y,Z>转换为Map <X,Z> - java8 convert Map<X,Y> + Map<Y,Z> to Map<X,Z> Java8:HashMap<x, y> 至 HashMap<x, z> 使用 Stream / Map-Reduce / 收集器</x,></x,> - Java8: HashMap<X, Y> to HashMap<X, Z> using Stream / Map-Reduce / Collector 怎么做地图<K, V>从流<Tuple2<K, V> &gt; 在 Java 流 API 中? - How to do Map<K, V> from Stream<Tuple2<K, V>> in java stream API? 如何使用java 8将Stream <Map <K,V >>收集到Map <K,List <V >>中? - How to collect Stream<Map<K,V>> into Map<K,List<V>> using java 8? Java 8转换地图 <K, List<V> &gt;到地图 <V, List<K> &gt; - Java 8 convert Map<K, List<V>> to Map<V, List<K>>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM