swift - Swift计算多维数组的维数

标签 swift multidimensional-array dimensions

假设我有一些函数,我想使用多维数组(例如 Tensor 类)填充我的数据结构:

class Tensor {
   init<A>(array:A) { /* ... */ }
}

虽然我可以添加一个 shape 参数,但我更愿意自动计算数组本身的维度。如果您先验地知道维度,那么读取它就很简单了:

let d1 = array.count
let d2 = array[0].count

但是,如何对 N 维数组执行此操作不太清楚。我在想可能有一种方法可以通过扩展 Array 类来实现:

extension Int {
   func numberOfDims() -> Int {
      return 0
   }
}

extension Array {
   func numberOfDims() -> Int {
     return 1+Element.self.numberOfDims()
   }
}

不幸的是,这不会(理所当然地)编译,因为 numberOfDims 没有为大多数类型定义。但是,我看不到任何限制 Element 的方法,因为 Arrays-of-Arrays 使事情变得复杂。

我希望其他人可能对如何解决这个问题有一些见解(或解释为什么这是不可能的)。

最佳答案

如果你想获得嵌套数组的深度(Swift 的标准库技术上不为你提供多维数组,只提供锯齿状数组)——那么,如 this Q&A 所示,您可以使用“虚拟协议(protocol)”和类型转换。

protocol _Array {
    var nestingDepth: Int { get }
}

extension Array : _Array {
    var nestingDepth: Int {
        return 1 + ((first as? _Array)?.nestingDepth ?? 0)
    }
}

let a = [1, 2, 3]
print(a.nestingDepth) // 1

let b = [[1], [2, 3], [4]]
print(b.nestingDepth) // 2

let c = [[[1], [2]], [[3]], [[4], [5]]]
print(c.nestingDepth) // 3

(我相信这种方法在您最初发布问题时仍然有效)

在 Swift 3 中,这也可以在没有虚拟协议(protocol)的情况下实现,而是通过转换为 [Any] 来实现。但是,如链接的问答中所述,这是低效的,因为它需要遍历整个数组才能将每个元素装入存在的容器中。

另请注意,此实现假定您是在同类嵌套数组上调用它。 As Paul notes ,它不会为 [[[1], 2], 3] 给出正确答案。

如果需要考虑这一点,您可以编写一个递归方法,该方法将遍历每个嵌套数组并返回嵌套的最小深度。

protocol _Array {
    func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int
}

extension Array : _Array {

    func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int {

        // for an empty array, the minimum depth is the current depth, as we know
        // that _nestingDepth is called where currentDepth <= minimumDepth.
        guard !isEmpty else { return currentDepth }

        var minimumDepth = minimumDepth

        for element in self {

            // if current depth has exceeded minimum depth, then return the minimum.
            // this allows for the short-circuiting of the function.
            if let minimumDepth = minimumDepth, currentDepth >= minimumDepth {
                return minimumDepth
            }

            // if element isn't an array, then return the current depth as the new minimum,
            // given that currentDepth < minimumDepth.
            guard let element = element as? _Array else { return currentDepth }

            // get the new minimum depth from the next nesting,
            // and incrementing the current depth.
            minimumDepth = element._nestingDepth(minimumDepth: minimumDepth,
                                                 currentDepth: currentDepth + 1)
        }

        // the force unwrap is safe, as we know array is non-empty, therefore minimumDepth 
        // has been assigned at least once.
        return minimumDepth!
    }

    var nestingDepth: Int {
        return _nestingDepth(minimumDepth: nil, currentDepth: 1)
    }
}

let a = [1, 2, 3]
print(a.nestingDepth) // 1

let b = [[1], [2], [3]]
print(b.nestingDepth) // 2

let c = [[[1], [2]], [[3]], [[5], [6]]]
print(c.nestingDepth) // 3

let d: [Any] = [ [[1], [2], [[3]] ], [[4]], [5] ]
print(d.nestingDepth) // 2 (the minimum depth is at element [5])

关于swift - Swift计算多维数组的维数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33664208/

相关文章:

java - java中如何将整数存储到字符串多维数组中

Android 启动器图标圆角边缘半径

matlab - 提取不规则物体的垂直和水平尺寸

ios - 无法将类型 'Swift.Array<Swift.Dictionary<Swift.String, Swift.String>>' () 的值转换为 'Swift.Dictionary<Swift.String, Any>' ()

ios - Swift 3 "didFinishPickingMediaWithInfo"用于 tableview 单元格内的图像

ios - Firebase 身份验证 (Swift 3) 的多个错误

ios - 快速具有多个部分的 TableView

php - 如何使用 PHP 文件中的信息动态更改页面的 HTML 内容?

Java Swing : How do I define one minimal dimension (of the two) for components?

ios - 为什么我的时间 UILabels 从暂停状态恢复播放时会跳过 2 秒?