如何在二维数组的范围上使用flatMap和reduce

问题描述

我有一个2d数组,我想使用类似于flatMap的东西,并将其与二维的范围缩小在一起。在我的示例中,我想将0至2行中位置1至3的每个数字相加。

目前,我的代码与以下代码相似,并且确实有效。

let array = [
     [3,6,8,4],[3,7,4,6],[2,5,7],[5,3,4]
]

let row = 1
let col = 2
var reducedValue = 0        
        
(row-1...row+1).forEach {
     reducedValue = array[$0][col-1...col+1].compactMap { $0 }.reduce(reducedValue,+)
}

预期输出为:

51
//6 + 8 + 4 + 7 + 4 + 6 + 4 + 5 + 7

但是我想知道是否有一种与此解决方案类似的解决方案:

reducedValue = array[row-1...row+1][col-1...col+1].compactMap { $0 }.reduce(0,+)

或者甚至没有类似于以下的compactMap:

reducedValue = array[row-1...row+1][col-1...col+1].reduce(0,+)

解决方法

您可以展平数组的数组,然后reduce。例如:

let total = array[row-1...row+1]
    .flatMap { $0[col-1...col+1] }
    .reduce(0,+)

结果是:

51


如果您想避免构建扁平化数组的开销(除非处理非常大的子数组,即数百万个值,否则这无关紧要),则可以懒惰地执行计算:

let total = array[row-1...row+1]
    .lazy
    .flatMap { $0[col-1...col+1] }
    .reduce(0,+)
,

另一个选项,不添加中间数组就添加选定行和列的值:

let value = array[row-1...row+1].reduce(0,{ $0 + $1[col-1...col+1].reduce(0,+) })
print(value) // 51

外部reduce()对选定的行进行迭代,并为每一行添加选定列中的值之和,这些值在内部reduce()中进行计算。

,

虽然功能性方法可以为您提供最简洁的代码

let result = array[row-1...row+1].reduce(into: 0) { $0 += $1[col-1...col+1].reduce(into: 0,+=) }

,经典命令式代码不应忽略:

var result = 0
for i in row-1...row+1 {
    for j in col-1...col+1 {
        result += array[i][j]
    }
}

命令式方法虽然比较冗长,但不是100%迅速的惯用语(当存在var替代项时使用let),但在此特定情况下更易于理解数学概念。