如何创建 3D NSMutableArray

How to create 3D NSMutableArray

如何创建 Int 的 3D 可变数组?

我希望能够通过说 arr[4][3][5] = 4 插入一个元素,而不必事先确定数组的大小。

var z = [Int](count:10, repeatedValue: 0)
var y = [[Int]](count:10, repeatedValue: z)
var x = [[[Int]]](count:10, repeatedValue: y)

x[A][B][C] = 4
var val = x[2][1][1]

Swift 3 in Xcode 8 beta 2 playground

var z = [Int](repeatElement(0, count: 10))
var y = [[Int]](repeatElement(z, count: 10))
var x = [[[Int]]](repeatElement(y, count: 10))

可能的答案

var z = [0]
var y = [z]
var x = [y]

x[0][0].append(2)

x[0].append([1])

x.append([[3,5],[0]])

print(x)

x[0][0][0] = 2

print(x)

//Output
[[[0, 2], [1]], [[3, 5], [0]]]
[[[2, 2], [1]], [[3, 5], [0]]]

讨论(最终代码见下文)

这里有一个方法:首先我们用一个下标扩展 _ArrayType ,当越界访问一个索引时,它会自动扩展数组。我们将数组给定 fallback 值:

extension _ArrayType {
    subscript (extending pos: Int, fallback fallback: Generator.Element) -> Generator.Element {
        mutating get {
            while count <= pos { append(fallback) }
            return self[pos]
        }
        mutating set {
            while count <= pos { append(fallback) }
            self[pos] = newValue
        }
    }
}

可以这样使用:

var a : [Int] = []
a[extending: 3, fallback: 0] = 10
print(a) // [0, 0, 0, 10]

现在我们可以扩展 3 维数组以获得一个方便的自动扩展的下标,如下所示:

extension _ArrayType where
    Generator.Element : _ArrayType,
    Generator.Element.Generator.Element : _ArrayType {

    typealias T = Generator.Element.Generator.Element.Generator.Element

    subscript (x: Int, y: Int, z: Int, `default`: T) -> T {
        mutating get {
            return self[extending: x, fallback: []][extending: y, fallback: []][extending: z, fallback: `default`]
        }
        mutating set {
            self[extending: x, fallback: []][extending: y, fallback: []][extending: z, fallback: `default`] = newValue
        }
    }
}

用法:

var array : [[[Int?]]] = []
array[1, 1, 0, nil] = 10
array[2, 0, 1, nil] = 4
print(array) // [[], [[], [Optional(10)]], [[nil, Optional(4)]]]

现在,如果您希望通过预先告知特定类型的默认值应该是什么来更方便,您可以创建一个 HasDefault 协议:

protocol HasDefault {
    static var `default` : Self { get }
}

并用它扩展你的类型:

extension Int : HasDefault {
    static var `default` = 0
}

extension Bool : HasDefault {
    static var `default` = false
}

也做一个不接受最后一个参数的下标:

extension _ArrayType where
    Generator.Element : _ArrayType,
    Generator.Element.Generator.Element : _ArrayType,
    Generator.Element.Generator.Element.Generator.Element : HasDefault {

    typealias E = Generator.Element.Generator.Element.Generator.Element

    subscript (x: Int, y: Int, z: Int) -> E {
        mutating get {
            return self[x, y, z, E.`default`]
        }
        mutating set {
            self[x, y, z, E.`default`] = newValue
        }
    }
}

现在可以按照您想要的方式使用它了:

var array : [[[Int]]] = []
array[0, 1, 0] = 3
array[1, 2, 3] = 10

print(array[2, 0, 1]) // 0
print(array) // [[[], [3]], [[], [], [0, 0, 0, 10]], [[0, 0]]]

不幸的是,(目前)还不能用 HasDefault(即 nil)扩展 Optional,但您可以为 NilLiteralConvertible 制作自定义下标Optional 符合:

extension _ArrayType where
    Generator.Element : _ArrayType,
    Generator.Element.Generator.Element : _ArrayType,
    Generator.Element.Generator.Element.Generator.Element : NilLiteralConvertible {

    subscript (x: Int, y: Int, z: Int) -> Generator.Element.Generator.Element.Generator.Element {
        mutating get {
            return self[x, y, z, nil]
        }
        mutating set {
            self[x, y, z, nil] = newValue
        }
    }
}

这样使用:

var array : [[[Int?]]] = []
array[0, 1, 0] = 3
array[1, 2, 3] = 10

print(array[2, 0, 1]) // nil
print(array) // [[[], [3]], [[], [], [nil, nil, nil, 10]], [[nil, nil]]]

我强烈推荐这种方法,因为 Optionals 的全部目的是不代表任何值。

TL;DR / 最终代码

extension _ArrayType {
    subscript (extending pos: Int, fallback fallback: Generator.Element) -> Generator.Element {
        mutating get {
            while count <= pos { append(fallback) }
            return self[pos]
        }
        mutating set {
            while count <= pos { append(fallback) }
            self[pos] = newValue
        }
    }
}

extension _ArrayType where
    Generator.Element : _ArrayType,
    Generator.Element.Generator.Element : _ArrayType,
    Generator.Element.Generator.Element.Generator.Element : NilLiteralConvertible {

    subscript (x: Int, y: Int, z: Int) -> Generator.Element.Generator.Element.Generator.Element {
        mutating get {
            return self[extending: x, fallback: []][extending: y, fallback: []][extending: z, fallback: nil]
        }
        mutating set {
            self[extending: x, fallback: []][extending: y, fallback: []][extending: z, fallback: nil] = newValue
        }
    }
}

var array : [[[Int?]]] = []
array[0, 1, 0] = 3
array[1, 2, 3] = 10

print(array[2, 0, 1]) // nil
print(array) // [[[], [3]], [[], [], [nil, nil, nil, 10]], [[nil, nil]]]