我将key作为String映射,将值映射为List。列表可以有10个唯一值。我需要将此映射转换为键为Integer,将值转换为List。示例如下:
输入:
"关键-1" :1,2,3,4
"关键-2" :2,3,4,5
"关键-3" :3,4,5,1
预期输出:
1:" Key-1"," Key-3"
2:" Key-1"," Key-2"
3:" Key-1"," Key-2"," Key-3"
4:" Key-1"," Key-2"," Key-3"
5:" Key-2"," Key-3"
我知道使用for循环我可以实现这一点,但我需要知道这可以通过java8中的streams / lamda完成。
-Thanks。
答案 0 :(得分:13)
一个想法可能是从原始地图生成所有价值密钥对,然后按这些值对密钥进行分组:
import java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
...
Map<Integer, List<String>> transposeMap =
map.entrySet()
.stream()
.flatMap(e -> e.getValue().stream().map(i -> new SimpleEntry<>(i, e.getKey())))
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
答案 1 :(得分:4)
Alexis’ answer包含此类任务的一般解决方案,使用flatMap
和临时持有者来组合键值和展平值。避免创建临时holder对象的唯一选择是重新实现groupingBy
收集器的逻辑并将循环插入值列表逻辑到累加器函数中:
Map<Integer, List<String>> mapT = map.entrySet().stream().collect(
HashMap::new,
(m,e) -> e.getValue().forEach(
i -> m.computeIfAbsent(i,x -> new ArrayList<>()).add(e.getKey())),
(m1,m2) -> m2.forEach((k,v) -> m1.merge(k, v, (l1,l2)->{l1.addAll(l2); return l1;})));
答案 2 :(得分:2)
这有点可怕(我通常试图将其分解以使其更具可读性)但你可以这样做:
transposeMap
假设{{1}}是您要转置的原始地图。 {{1}}会转换您需要的地图。
答案 3 :(得分:2)
你可以通过这种方式实现
假设我有Person和Gender和Age。我希望以这种形式获得它
Map<SEX,List<Person>>
我会写简单
Map<SEX,List<Person>> map = personList.stream()
.collect(Collectors.groupingBy(Person::getGender));
它会让我得到类似下面的内容(一个键可以反对多个值)
key:MALE
age31sexMALE
age28sexMALE
key:FEMALE
age40sexFEMALE
age44sexFEMALE
答案 4 :(得分:0)
with teeing
您可以分别处理 2 个流中的键和值
从 Java 12 开始
Map<Integer, List<String>> to = from.entrySet().stream()
.collect(teeing(flatMapping(e -> e.getValue().stream(), toList()),
flatMapping(e -> (Stream<String>)e.getValue().stream().map(i -> e.getKey()), toList()),
(k, v) -> {
return IntStream.range(0, k.size()).boxed().collect(
groupingBy(i -> k.get(i), mapping(i -> v.get(i), toList())));
}));