[英]N-Dimensional array swift
有沒有辦法在swift中有一個n維數組? 我希望能夠創建一個創建一個n維數組的函數,但我無法弄清楚如何。
基本上是這樣的:
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
}
以上代碼不適用於obvios原因,但我認為它指出了我遇到的主要問題:
這是N維數組的實現。 它在內部使用普通數組進行存儲,並將多維索引轉換為內部數組的單個索引。
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)” ]
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在評論中指出的那樣,在初始化具有引用類型值的數組時必須小心,因為數組將填充對對象的引用,並且修改任何索引處的對象將修改所有這些對象。
為了解決這個問題,我添加了第二個初始化器:
init(dimensions: Int..., initUsing initializer: () -> T)
它接受一個closure () -> T
,它可以用來為數組的每個元素創建一個新對象。
例如:
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)
弗雷德威爾瑪
不,這是不可能的。 數組維度需要在編譯時確定,而要傳遞給初始值設定項的參數在運行時才會知道。 如果你真的想要實現這樣的東西,那么你需要將數組索引從編譯時移動到運行時,例如通過索引數組訪問數組。 您仍然沒有編譯驗證,因為數組長度在運行時可能與數組的維度不匹配。
此問題類似於嘗試將元組轉換為數組的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.