如何展开Java Map的条目流以生成指定格式的键值对序列
如何展开Java Map的条目流以生成指定格式的键值对序列
嗨,我来给你捋捋怎么实现这个需求~ 简单来说就是要把Map里的每个键值对,根据值的大小“拆”成N个新的键值对,每个新对的键不变,值从1递增到原Map里对应的值对吧?
用Java Stream就能很优雅地搞定,核心思路就是对每个Map条目,生成一个从1到对应值的整数流,再把每个整数和原键组合成新的键值对,最后把所有这些小流合并成一个大流。
直接上代码示例,你可以直接跑起来验证:
import java.util.AbstractMap; import java.util.Map; import java.util.stream.Stream; public class MapInflationDemo { public static void main(String[] args) { // 你的原始Map Map<String, Integer> sourceMap = Map.of( "A", 5, "C", 13, "E", 2, "M", 5, "T", 45, "W", 2 ); // 生成展开后的流 Stream<Map.Entry<String, Integer>> inflatedStream = sourceMap.entrySet() .stream() // 对每个entry,展开成多个元素 .flatMap(entry -> // 生成从1到entry.getValue()的整数流(包含两端) IntStream.rangeClosed(1, entry.getValue()) // 把每个整数和原key包装成键值对 .mapToObj(i -> new AbstractMap.SimpleEntry<>(entry.getKey(), i)) ); // 按你要的格式打印结果 inflatedStream.forEach(entry -> System.out.printf("\"%s\", %d,%n", entry.getKey(), entry.getValue()) ); } }
给你拆解下关键部分:
flatMap是这里的核心,它能把每个entry产生的小流(每个entry对应N个元素的流)合并成一个整体的流,不会出现嵌套流的问题IntStream.rangeClosed(1, entry.getValue())一定要用rangeClosed,因为它包含结束值,如果你用range的话,只会生成到value-1,就少了最后一个元素- 用
AbstractMap.SimpleEntry是因为Java标准库已经提供了现成的键值对实现,如果你用的是Java 16及以上版本,也可以自己定义一个更清晰的记录类:
然后把record KeyNumber(String key, int number) {}mapToObj里的代码改成i -> new KeyNumber(entry.getKey(), i),这样代码可读性会更好。
另外提个小细节:如果你的原始Map里有可能出现值为0或者负数的情况,可以在flatMap之前加个过滤:
.filter(entry -> entry.getValue() > 0)
这样就不会生成无效的元素啦。
备注:内容来源于stack exchange,提问作者Jin Kwon
相关产品推荐
相关产品推荐

