如何用Kotlin函数式方式提取n阶矩阵中的m阶重叠子矩阵(m<n)
Kotlin函数式提取矩阵中m阶重叠子矩阵
给定示例矩阵:
val matrix = listOf( listOf(1, 2, 3, 4), listOf(5, 6, 7, 8), listOf(9, 1, 2, 3) )
要提取所有m×m大小的重叠子矩阵,可以利用Kotlin标准库的windowed函数实现纯函数式写法,甚至可以压缩为一行代码。
核心实现(一行代码)
matrix.windowed(m).flatMap { rowWindow -> rowWindow.map { it.windowed(m) }.let { colWindows -> colWindows.first().indices.map { c -> colWindows.map { it[c] } } } }
分步解释
- 获取行窗口:
matrix.windowed(m)提取原矩阵中连续m行的滑动窗口,每个窗口是一个包含m行的子矩阵(List<List<Int>>)。 - 拆分每行的列窗口:对每个行窗口,
rowWindow.map { it.windowed(m) }将每行拆分为长度为m的滑动窗口,得到一个List<List<List<Int>>>结构——外层是m行,中层是每行的所有m长度列窗口。 - 组合子矩阵:通过
colWindows.first().indices.map { c -> colWindows.map { it[c] } },将m行中同一位置的列窗口组合成完整的m×m子矩阵,最后用flatMap将所有子矩阵平铺到一个列表中。
补充:转置扩展函数简化写法
如果觉得一行代码过于紧凑,可以定义一个转置扩展函数来优化可读性:
fun <T> List<List<T>>.transpose(): List<List<T>> { return first().indices.map { colIndex -> map { it[colIndex] } } }
此时提取子矩阵的代码可以简化为:
matrix.windowed(m).flatMap { it.map { row -> row.windowed(m) }.transpose() }
验证示例(m=3)
对于给定的3行4列矩阵,m=3时会得到两个3×3子矩阵:
[[1,2,3], [5,6,7], [9,1,2]][[2,3,4], [6,7,8], [1,2,3]]
原命令式代码的问题修正
原命令式代码存在几处错误,修正后如下:
val result = mutableListOf<List<List<Int>>>() val rowCount = matrix.size val colCount = matrix.first().size for (i in 0 until rowCount - m + 1) { for (j in 0 until colCount - m + 1) { val subMatrix = mutableListOf<List<Int>>() for (k in i until i + m) { val row = mutableListOf<Int>() for (l in j until j + m) { row.add(matrix[k][l]) } subMatrix.add(row) } result.add(subMatrix) } }
- 修正了循环范围:需用
until rowCount - m + 1才能覆盖所有可能的起始位置 - 修正了元素引用:
matrix[m][n]改为matrix[k][l] - 改为真正的二维子矩阵存储,而非一维列表
内容的提问来源于stack exchange,提问作者Alexander Ites
相关产品推荐
相关产品推荐

