嵌套数据结构两类通用转换需求:求JVM生态实现方案
两类嵌套数据结构转换的名称与JVM语言实现
转换名称定义
- 第一类:嵌套Map转置(Transpose Nested Map),你猜测的“转置”是准确的,把嵌套Map看作X行Y列的矩阵,转置后就是Y行X列的矩阵。
- 第二类:多值映射反转(Inverse Multimap),将单键多值的映射反转成单值多键的映射。
Java实现方案
1. 嵌套Map转置
原生Stream实现
import java.util.Map; import java.util.stream.Collectors; public class MapTransposer { public static <X, Y, Z> Map<Y, Map<X, Z>> transposeNestedMap(Map<X, Map<Y, Z>> input) { return input.entrySet().stream() .flatMap(xEntry -> xEntry.getValue().entrySet().stream() .map(yEntry -> Map.entry(yEntry.getKey(), Map.entry(xEntry.getKey(), yEntry.getValue())))) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.toMap( nestedEntry -> nestedEntry.getValue().getKey(), nestedEntry -> nestedEntry.getValue().getValue() ) )); } // 测试示例 public static void main(String[] args) { Map<String, Map<String, Integer>> input = Map.of( "a", Map.of("X", 1, "Y", 2), "b", Map.of("Y", 3) ); Map<String, Map<String, Integer>> output = transposeNestedMap(input); System.out.println(output); // 输出:{X={a=1}, Y={a=2, b=3}} } }
第三方库方案(Guava)
Guava可借助Multimap间接实现转置:
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import java.util.Map; public class GuavaMapTranspose { public static <X, Y, Z> Map<Y, Map<X, Z>> transposeWithGuava(Map<X, Map<Y, Z>> input) { Multimap<Y, Map.Entry<X, Z>> tempMultimap = ArrayListMultimap.create(); input.forEach((x, yzMap) -> yzMap.forEach((y, z) -> tempMultimap.put(y, Map.entry(x, z)))); return Multimaps.asMap(tempMultimap).entrySet().stream() .collect(Map::ofEntries, (map, entry) -> map.put(entry.getKey(), entry.getValue().stream().collect(Map::ofEntries, (innerMap, e) -> innerMap.put(e.getKey(), e.getValue()), Map::putAll)), Map::putAll); } }
2. 多值映射反转
原生Stream实现
import java.util.Map; import java.util.Set; import java.util.stream.Collectors; public class InvertMultiMap { public static <X, Y> Map<Y, Set<X>> invertMultiMap(Map<X, Set<Y>> input) { return input.entrySet().stream() .flatMap(xEntry -> xEntry.getValue().stream() .map(y -> Map.entry(y, xEntry.getKey()))) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.mapping( Map.Entry::getValue, Collectors.toSet() ) )); } // 测试示例 public static void main(String[] args) { Map<String, Set<String>> input = Map.of( "a", Set.of("X", "Y"), "b", Set.of("Y", "Z") ); Map<String, Set<String>> output = invertMultiMap(input); System.out.println(output); // 输出:{X=[a], Y=[a, b], Z=[b]} } }
第三方库方案(Guava)
Guava的Multimap原生支持反转,是最便捷的方案:
import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import java.util.Map; import java.util.Set; public class GuavaInvertMultiMap { public static <X, Y> Map<Y, Set<X>> invertWithGuava(Map<X, Set<Y>> input) { Multimap<X, Y> multimap = HashMultimap.create(); input.forEach(multimap::putAll); return Multimaps.asMap(Multimaps.invertFrom(multimap, HashMultimap.create())); } }
Groovy实现方案
Groovy语法糖可大幅简化代码:
1. 嵌套Map转置
def transposeNestedMap(Map input) { input.collectMany { x, yzMap -> yzMap.collect { y, z -> [y, [x, z]] } }.groupBy { it[0] }.collectEntries { y, entries -> [y, entries.collectEntries { [it[1][0], it[1][1]] }] } } // 测试 def input = [a: [X:1, Y:2], b: [Y:3]] println transposeNestedMap(input) // 输出:[X:[a:1], Y:[a:2, b:3]]
2. 多值映射反转
def invertMultiMap(Map input) { input.collectMany { x, ys -> ys.collect { y -> [y, x] } } .groupBy { it[0] } .collectEntries { y, xs -> [y, xs*.getAt(1) as Set] } } // 测试 def input = [a: ['X', 'Y'] as Set, b: ['Y', 'Z'] as Set] println invertMultiMap(input) // 输出:[X:[a], Y:[a, b], Z:[b]]
Clojure实现方案
Clojure核心库提供函数式简洁实现:
1. 嵌套Map转置
(defn transpose-nested-map [input] (->> input (mapcat (fn [[x yz-map]] (map (fn [[y z]] [y [x z]]) yz-map))) (group-by first) (reduce (fn [acc [y entries]] (assoc acc y (into {} (map (fn [[_ [x z]]] [x z]) entries)))) {}))) ;; 测试 (def input {"a" {"X" 1, "Y" 2}, "b" {"Y" 3}}) (println (transpose-nested-map input)) ; 输出:{"X" {"a" 1}, "Y" {"a" 2, "b" 3}}
2. 多值映射反转
(defn invert-multi-map [input] (->> input (mapcat (fn [[x ys]] (map (fn [y] [y x]) ys))) (group-by first) (reduce (fn [acc [y xs]] (assoc acc y (set (map second xs)))) {}))) ;; 测试 (def input {"a" #{"X" "Y"}, "b" #{"Y" "Z"}}) (println (invert-multi-map input)) ; 输出:{"X" #{"a"}, "Y" #{"a" "b"}, "Z" #{"b"}}
内容的提问来源于stack exchange,提问作者Ionut Bilica
相关产品推荐
相关产品推荐

