问题描述
我有一个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
),但在此特定情况下更易于理解数学概念。