Java:如何仅使用Streams实现List<List<Double>>的转置
用Java Streams优雅转置List<List>
嘿,我懂你想要纯靠Streams来实现List<List<Double>>的转置,不想搞自定义对象这种不够优雅的操作——这事儿完全能搞定!
先明确下你的需求例子:假设原列表是[[1.0,2.0,3.0,4.0], [5.0,6.0,7.0,8.0]],你想要的转置后展开结果是[1.0,5.0,2.0,6.0,3.0,7.0,4.0,8.0],也就是按列取元素再依次排列对吧?
核心实现代码
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public class StreamTransposeDemo { public static void main(String[] args) { List<List<Double>> original = Arrays.asList( Arrays.asList(1.0, 2.0, 3.0, 4.0), Arrays.asList(5.0, 6.0, 7.0, 8.0) ); // 转置并展开成目标序列 List<Double> transposedResult = IntStream.range(0, original.get(0).size()) // 遍历每一列索引,生成转置后的子列表 .mapToObj(colIdx -> original.stream() .map(row -> row.get(colIdx)) .collect(Collectors.toList()) ) // 把所有转置后的子列表展开成连续流 .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(transposedResult); // 输出 [1.0, 5.0, 2.0, 6.0, 3.0, 7.0, 4.0, 8.0] } }
代码逻辑拆解
- 生成列索引流:用
IntStream.range(0, original.get(0).size())遍历原列表的每一列位置,这是转置的核心——我们要按列而非按行取元素。 - 构建转置子列表:对于每个列索引,遍历原列表的所有行,取出对应列的元素并收集成子列表,这一步就完成了“列转行”的转置操作。
- 展开成目标序列:用
flatMap(List::stream)把所有转置后的子列表拼接成一个连续的元素流,最后收集成你需要的List<Double>。
处理行长度不一致的情况
如果原列表的子列表长度可能不一样,直接取索引会报错,我们可以先计算最长列数,用默认值填充缺失的元素:
int maxColumnCount = original.stream().mapToInt(List::size).max().orElse(0); List<Double> transposedWithFill = IntStream.range(0, maxColumnCount) .mapToObj(colIdx -> original.stream() .map(row -> colIdx < row.size() ? row.get(colIdx) : 0.0) // 用0.0填充缺失值,可按需修改 .collect(Collectors.toList()) ) .flatMap(List::stream) .collect(Collectors.toList());
这个方案完全不需要自定义对象,纯靠Streams API实现,代码简洁且符合函数式编程的声明式风格,比迭代方案更优雅易读。
内容的提问来源于stack exchange,提问作者Julien BERNARD
相关产品推荐
相关产品推荐

