在Swift中计算多维数组的维数 [英] Calculate the number of dimensions of a multi-dimensional array in Swift

查看:188
本文介绍了在Swift中计算多维数组的维数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Suppose I have some function that I want to populate my data structure using a multi-dimensional array (e.g. a Tensor class):

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

虽然我可以添加一个 shape 参数,但我还是希望根据数组本身自动计算尺寸。如果您知道先验的尺寸,那么将其读起来很简单:

while I could add in a shape parameter, I would prefer to automatically calculate the dimensions from the array itself. If you know apriori the dimensions, it's trivial to read it off:

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

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

However, it's less clear how to do it for an N-dimensional array. I was thinking there might be a way to do it by extending the Array class:

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

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

不幸的是,这不会(理应如此)编译,因为大多数类型都没有定义 numberOfDims 。但是,我看不到任何约束 Element 的方法,因为Arrays-of-Arrays使事情变得复杂。

Unfortunately, this won't (rightfully so) compile, as numberOfDims isn't defined for most types. However, I'm don't see any way of constraining Element, as Arrays-of-Arrays make things complicated.

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

I was hoping someone else might have some insight into how to solve this problem (or explain why this is impossible).

推荐答案

如果您想获取嵌套数组的深度(Swift的标准库从技术上讲不是 为您提供多维数组,而只是锯齿状的数组)–然后,如此问题与解答,您可以使用虚拟协议并进行类型转换。

If you're looking to get the depth of a nested array (Swift's standard library doesn't technically provide you with multi-dimensional arrays, only jagged arrays) – then, as shown in this Q&A, you can use a 'dummy protocol' and typecasting.

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] 。但是,正如在链接的问答中所指出的那样,这种方法效率低下,因为它需要遍历整个数组以便将每个元素装在一个存在的容器中。

In Swift 3, this can also be achieved without a dummy protocol, but instead by casting to [Any]. However, as noted in the linked Q&A, this is inefficient as it requires traversing the entire array in order to box each element in an existential container.

此实现假定,您是在同质嵌套数组上调用它。 如Paul所述,对于 [[[1],2 ],3]

Also note that this implementation assumes that you're calling it on a homogenous nested array. As Paul notes, it won't give a correct answer for [[[1], 2], 3].

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

If this needs to be accounted for, you could write a recursive method which will iterate through each of the nested arrays and returning the minimum depth of the nesting.

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中计算多维数组的维数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆