N维数组快速 [英] N-Dimensional array swift

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

问题描述

有什么办法可以快速建立n维数组?我希望能够创建一个可以创建具有n个维度的数组的函数,但是我不知道该怎么做.

Is there any way to have an n dimensional array in swift? I would like to be able to make a function that creates an array with n dimensions but I cannot figure out how.

基本上是这样的:

func ndarray <T> (dimensions: Int...) -> [[T]] { // What do I tell it I return?
    var out
    for d in dimensions {
        out = Array<T>(repeating: out, count: d)
    }
    return out
} 

以上代码出于种种原因无法正常运行,但是,我认为它指出了我遇到的主要问题:

The above code does not work for obvios reasons but, I think it points out the main problems I am having:

  • 如何定义返回类型
  • 如何实际创建数组
  • 创建后如何遍历并填充数组

推荐答案

这里是N维数组的实现.它在内部使用普通数组进行存储,并将多维索引转换为内部数组的单个索引.

Here is the implementation of an N-Dimensional Array. It uses a normal array internally for storage and converts the multi-dimensional indices into a single index for the internal array.

struct NDimArray<T> {
    let dimensions: [Int]
    var data: [T]

    init(dimensions: Int..., initialValue: T) {
        self.dimensions = dimensions
        data = Array(repeating: initialValue, count: dimensions.reduce(1, *))
    }

    init(dimensions: Int..., initUsing initializer: () -> T) {
        self.dimensions = dimensions
        data = (0 ..< dimensions.reduce(1, *)).map { _ in initializer() }
    }

    // Compute index into data from indices
    private func computeIndex(_ indices: [Int]) -> Int {
        guard indices.count == dimensions.count else { fatalError("Wrong number of indices: got \(indices.count), expected \(dimensions.count)") }
        zip(dimensions, indices).forEach { dim, idx in
            guard (0 ..< dim) ~= idx else { fatalError("Index out of range") }
        }

        var idx = indices
        var dims = dimensions
        var product = 1
        var total = idx.removeLast()
        while !idx.isEmpty {
            product *= dims.removeLast()
            total += (idx.removeLast() * product)
        }

        return total
    }

    subscript(_ indices: Int...) -> T {
        get {
            return data[computeIndex(indices)]
        }
        set {
            data[computeIndex(indices)] = newValue
        }
    }
}

示例:

// Create a 3 x 4 x 5 array of String with initial value ""

var arr = NDimArray<String>(dimensions: 3, 4, 5, initialValue: "")
for x in 0 ..< 3 {
    for y in 0 ..< 4 {
        for z in 0 ..< 5 {
            // Encode indices in the string
            arr[x, y, z] = "(\(x),\(y),\(z))"
        }
    }
}


// Show internal storage of data
print(arr.data)

[(0,0,0)",(0,0,1)",(0,0,2)",(0,0,3)",(0,0, 4),"(0,1,0),"(0,1,1),"(0,1,2),"(0,1,3),"(0,1, 4),"(0,2,0),"(0,2,1),"(0,2,2),"(0,2,3),"(0,2, 4),"(0,3,0),"(0,3,1),"(0,3,2),"(0,3,3),"(0,3, 4)",((1,0,0)",(1,0,1)",(1,0,2)",(1,0,3)",(1,0, 4),"(1,1,0),"(1,1,1),"(1,1,2),"(1,1,3),"(1,1, 4),"(1,2,0),"(1,2,1),"(1,2,2),"(1,2,3),"(1,2, 4),"(1,3,0),"(1,3,1),"(1,3,2),"(1,3,3),"(1,3, 4),"(2,0,0),"(2,0,1),"(2,0,2),"(2,0,3),"(2,0, 4),"(2,1,0),"(2,1,1),"(2,1,2),"(2,1,3),"(2,1, 4),"(2,2,0),"(2,2,1),"(2,2,2),"(2,2,3),"(2,2, 4),"(2,3,0),"(2,3,1),"(2,3,2),"(2,3,3),"(2,3, 4)]

["(0,0,0)", "(0,0,1)", "(0,0,2)", "(0,0,3)", "(0,0,4)", "(0,1,0)", "(0,1,1)", "(0,1,2)", "(0,1,3)", "(0,1,4)", "(0,2,0)", "(0,2,1)", "(0,2,2)", "(0,2,3)", "(0,2,4)", "(0,3,0)", "(0,3,1)", "(0,3,2)", "(0,3,3)", "(0,3,4)", "(1,0,0)", "(1,0,1)", "(1,0,2)", "(1,0,3)", "(1,0,4)", "(1,1,0)", "(1,1,1)", "(1,1,2)", "(1,1,3)", "(1,1,4)", "(1,2,0)", "(1,2,1)", "(1,2,2)", "(1,2,3)", "(1,2,4)", "(1,3,0)", "(1,3,1)", "(1,3,2)", "(1,3,3)", "(1,3,4)", "(2,0,0)", "(2,0,1)", "(2,0,2)", "(2,0,3)", "(2,0,4)", "(2,1,0)", "(2,1,1)", "(2,1,2)", "(2,1,3)", "(2,1,4)", "(2,2,0)", "(2,2,1)", "(2,2,2)", "(2,2,3)", "(2,2,4)", "(2,3,0)", "(2,3,1)", "(2,3,2)", "(2,3,3)", "(2,3,4)"]

print(arr[2, 2, 2])  // "(2,2,2)"
print(arr[3, 0, 0])  // Fatal error: Index out of range
print(arr[0, 4, 0])  // Fatal error: Index out of range
print(arr[2])        // Fatal error: Wrong number of indices: got 1, expected 3


使用引用类型初始化数组

正如@DuncanC在注释中指出的那样,在初始化带有引用类型值的数组时必须要小心,因为该数组将填充对对象的引用,并且在任何索引处修改该对象都会修改所有对象.其中

As @DuncanC noted in the comments, you have to be careful when initializing an array with a value which is a reference type, because the array will be filled with references to the object and modifying the object at any index will modify all of them.

为解决此问题,我添加了第二个初始化程序:

To solve this, I added a second initializer:

init(dimensions: Int..., initUsing initializer: () -> T)

带一个闭包() -> T,可用于为数组的每个元素创建一个新对象.

which takes a closure () -> T which can be used to create a new object for each element of the array.

例如:

class Person {
    var name = ""
}

// Pass a closure which creates a `Person` instance to fill the array
// with 25 person objects   
let arr = NDimArray(dimensions: 5, 5, initUsing: { Person() })
arr[3, 3].name = "Fred"
arr[2, 2].name = "Wilma"

print(arr[3, 3].name, arr[2, 2].name)

弗雷德·威尔玛

Fred Wilma

这篇关于N维数组快速的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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