Swift - 如何减少矩阵

Swift - how to reduce matrix

我有一个 3 维数组(array[x][y][z]x y z 可以灵活)

var array = [ [[1,1,1],[0,0,0],[1,1,1]],
              [[1,0,1],[1,0,1],[1,0,1]],
              [[1,1,1],[0,0,0],[1,1,1]]
            ]

如何将 3D 缩小为 2D 以:array[z][y]

[3,1,3],[2,0,2],[3,1,3]

我阅读了说明 但不知道如何应用到我的。

更新: 这是逻辑

鉴于此

let matrix = [
    [[1,1,1],[0,0,0],[1,1,1]],
    [[1,0,1],[1,0,1],[1,0,1]],
    [[1,1,1],[0,0,0],[1,1,1]]
]

让我们计算这些

let all = matrix.joined().enumerated()

let a = all.filter { [=11=].offset % 3 == 0 }.map { [=11=].element[0] }.reduce(0, +)
let b = all.filter { [=11=].offset % 3 == 1 }.map { [=11=].element[0] }.reduce(0, +)
let c = all.filter { [=11=].offset % 3 == 2 }.map { [=11=].element[0] }.reduce(0, +)

let d = all.filter { [=11=].offset % 3 == 0 }.map { [=11=].element[1] }.reduce(0, +)
let e = all.filter { [=11=].offset % 3 == 1 }.map { [=11=].element[1] }.reduce(0, +)
let f = all.filter { [=11=].offset % 3 == 2 }.map { [=11=].element[1] }.reduce(0, +)

let g = all.filter { [=11=].offset % 3 == 0 }.map { [=11=].element[2] }.reduce(0, +)
let h = all.filter { [=11=].offset % 3 == 1 }.map { [=11=].element[2] }.reduce(0, +)
let i = all.filter { [=11=].offset % 3 == 2 }.map { [=11=].element[2] }.reduce(0, +)

最后让我们把这些值放在一起[=13​​=]

let res = [[a, b, c], [d, e, f], [g, h, i]]

因为听起来您正在寻找函数式编程的单行代码,所以这是您的答案:

array.indices.map{ j in array.indices.map{ i in array.map{ [=10=][i][j] }.reduce(0, +) } }

它与这段代码基本相同,虽然更长,但我认为它更容易阅读并且让我在推理时更少头疼。

func flatten2(_ array:[[[Int]]]) -> [[Int]]
{
    var result:[[Int]] = []
    for j in 0..<array.count
    {
        var row:[Int] = []
        for i in 0..<array.count
        {
            row.append(array.map{ [=11=][i][j] }.reduce(0, +))
        }
        result.append(row)
    }
    return result
}

请记住,单行代码的编译时间要长两个数量级,因为 Swift 编译器对于函数式和闭包编程不是很优化,所以它必须构建巨大的重载树解析该表达式。因为我怀疑这是CS期末练习题,拜托,拜托,让你可怜的TA生活更轻松,使用多行。

让我们首先形成一个效用函数作为矩阵式数组的扩展("cw" 表示按列):

extension Array where Element == [[Int]] {
    func cwsum(_ ix1:Int, _ ix2:Int) -> Int {
        return reduce(0) {[=10=] + [ix1][ix2]}
    }
}

那么如果数组是:

let array = [[[1,1,1],[0,0,0],[1,1,1]],
             [[1,0,1],[1,0,1],[1,0,1]],
             [[1,1,1],[0,0,0],[1,1,1]]]

...那么答案是:

[[array.cwsum(0,0), array.cwsum(1,0), array.cwsum(2,0)],
 [array.cwsum(0,1), array.cwsum(1,1), array.cwsum(2,1)],
 [array.cwsum(0,2), array.cwsum(1,2), array.cwsum(2,2)]] 
// [[3, 1, 3], [2, 0, 2], [3, 1, 3]]

但是等等——我想我在这里看到了一个规律!我们可以重写它而无需对索引进行硬编码,如:

var result = [[Int]]()
for j in 0..<3 {
    var r1 = [Int]()
    for i in 0..<3 {
        r1.append(array.cwsum(i,j))
    }
    result.append(r1)
} // result is now [[3, 1, 3], [2, 0, 2], [3, 1, 3]]

好的,但是在我们可以循环和 append 的地方,我们可以 map 代替,从而将 i 变成映射变量:

var result = [[Int]]()
for j in 0..<3 {
    result.append((0..<3).map{i in array.cwsum(i,j)})
}

但是我们也可以为 j 这样做——因此它变成了一行:

result = (0..<3).map{j in (0..<3).map{i in array.cwsum(i,j)}}

经过几个小时的尝试。这是我的输出,它非常简单并且与 reduce 无关。 3d数组的输入是灵活的x,y,z

    let x = array.count
    let y = array[0].count
    let z = array[0][0].count

    var final = Array(repeating: Array(repeating: 0, count: y), count: z)
    for i in 0..<z {
        for ii in 0..<y {
            var sum = 0
            for iii in 0..<x {
                sum = sum + array[iii][ii][i]
            }
            final[i][ii] = sum
        }

    }