在Swift中计算多维数组的维数

在Swift中计算多维数组的维数,swift,multidimensional-array,dimensions,Swift,Multidimensional Array,Dimensions,假设我有一些函数,我想使用多维数组(例如,张量类)填充我的数据结构: 然而,对于N维数组,如何实现这一点还不太清楚。我想有一种方法可以通过扩展Array类来实现: extension Int { func numberOfDims() -> Int { return 0 } } extension Array { func numberOfDims() -> Int { return 1+Element.self.numberOfDims()

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

然而,对于N维数组,如何实现这一点还不太清楚。我想有一种方法可以通过扩展Array类来实现:

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

extension Array {
   func numberOfDims() -> Int {
     return 1+Element.self.numberOfDims()
   }
}
不幸的是,这不会(正确地)编译,因为大多数类型都没有定义
numberOfDims
。然而,我不认为有任何方法可以约束
元素
,因为数组的数组使事情变得复杂


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

不幸的是,我无法使用Swift数组实现这一点,但您可以轻松地将Swift数组转换为NSArray

extension NSArray {
    func numberOfDims() -> Int {
        var count = 0
        if let x = self.firstObject as? NSArray {
            count += x.numberOfDims() + 1
        } else {
            return 1
        }
        return count
    }
}

这个问题真是太好了,把我吓得魂飞魄散

需要明确的是:我下面讨论的是使用最外层数组的泛型类型参数来计算维数的方法。正如Tyrelidrel所展示的,您可以递归地检查第一个元素的运行时类型——尽管这种方法对于异类数组(如
[[1],2],3]
)给出了毫无意义的答案

基于类型的分派无法工作 正如您所注意到的,您编写的代码不起作用,因为没有为所有类型定义
numberOfDims
。但是有解决办法吗?这个方向通向哪里

不,这是一条死胡同。原因是扩展方法是为非类类型静态调度的,如下代码段所示:

extension CollectionType {
  func identify() {
    print("I am a collection of some kind")
  }

  func greetAndIdentify() {
    print("Hello!")
    identify()
  }
}

extension Array {
  func identify() {
    print("I am an array")
  }
}

[1,2,3].identify()         // prints "I am an array"
[1,2,3].greetAndIdentify() // prints "Hello!" and "I am a collection of some kind"
即使Swift允许您扩展
Any
(而且它不允许),
Element.self.numberOfDims()
将始终调用
Any
实现
numberOfDims()
,即使
Element.self
的运行时类型是数组

这种极具破坏性的静态分派限制意味着即使这种看起来很有前途的方法也会失败(它编译,但总是返回1):

同样的约束也适用于函数重载

型式检验不起作用 如果有一种方法可以让它工作的话,它可以是这样的,即使用条件方法而不是基于类型的方法分派来遍历嵌套的数组类型:

extension Array {
  var numberOfDims: Int {
    return self.dynamicType.numberOfDims
  }

  static var numberOfDims: Int {
    if let nestedArrayType = Generator.Element.self as? Array.Type {
        return 1 + nestedArrayType.numberOfDims
    } else {
        return 1
    }
  }
}

[[1,2],[2],[3]].numberOfDims
上面的代码编译起来相当混乱,因为Swift将
Array.Type
作为
Array.Type
的快捷方式。这完全挫败了打开包装的企图

解决办法是什么?没有。这种方法不起作用,因为我们需要说“如果
元素
是某种
数组
”,但据我所知,在Swift中没有办法说“任何数组”,或者“不管
元素
,都只能说
数组
类型”

无论您在哪里提到
数组
类型,其泛型类型参数都必须在编译时具体化为具体类型或协议

作弊可以奏效 那么,反思呢?有办法。这不是一个好办法,但总有办法的。Swift的
Mirror
目前还不足以告诉我们元素类型是什么,但是还有另一种足够强大的反射方法:将类型转换为字符串

private let arrayPat = try! NSRegularExpression(pattern: "Array<", options: [])

extension Array {
  var numberOfDims: Int {
    let typeName = "\(self.dynamicType)"
    return arrayPat.numberOfMatchesInString(
        typeName, options: [], range: NSMakeRange(0, typeName.characters.count))
  }
}

private让arrayPat=try!NSRegularExpression(模式:“Array如果您希望获得嵌套数组的深度(Swift的标准库在技术上不提供多维数组,仅提供锯齿数组)–然后,如中所示,您可以使用“虚拟协议”和类型转换

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中,这也可以在没有虚拟协议的情况下实现,但可以通过强制转换到
[Any]
来实现。然而,正如链接问答中所指出的,这是低效的,因为它需要遍历整个数组才能将每个元素装箱到存在容器中

还请注意,此实现假定您在同质嵌套数组上调用它,它不会给出
[[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])
protocol\u数组{
函数嵌套深度(最小深度:Int?,当前深度:Int)->Int
}
扩展数组:\u数组{
函数嵌套深度(最小深度:Int?,当前深度:Int)->Int{
//如我们所知,对于空数组,最小深度是当前深度
//该_nestingDepth称为currentDepth=minimumDepth{
返回最小深度
}
//如果元素不是数组,则返回当前深度作为新的最小值,
//假设currentDepth
我知道我看到过对
dynamicType
的引用,这些引用看起来像是试图让您的顶级解决方案这样的案例发挥作用。不幸的是,我找不到关于它的好文档,也找不到让它发挥作用的方法
private let arrayPat = try! NSRegularExpression(pattern: "Array<", options: [])

extension Array {
  var numberOfDims: Int {
    let typeName = "\(self.dynamicType)"
    return arrayPat.numberOfMatchesInString(
        typeName, options: [], range: NSMakeRange(0, typeName.characters.count))
  }
}
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
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])