Swift 2D Array Performance
If you really want to stick to a 2D array then you can use unsafe buffer pointers for faster access. However, 1D arrays are still going to be more efficient. Give this a shot.
// 2D array assignment
myArray1.withUnsafeMutableBufferPointer { outer1 -> Void in
for i in 0..<numberOfItems {
outer1[i].withUnsafeMutableBufferPointer { inner1 -> Void in
for j in 0..<numberOfItems {
inner1[j] = x
x += 1
}
}
}
}
// 2D array access and assignment
myArray1.withUnsafeMutableBufferPointer { outer1 -> Void in
myArray2.withUnsafeMutableBufferPointer { outer2 -> Void in
for i in 0..<numberOfItems {
outer1[i].withUnsafeMutableBufferPointer { inner1 -> Void in
outer2[i].withUnsafeMutableBufferPointer { inner2 -> Void in
for j in 0..<numberOfItems {
inner2[j] = inner1[j]
}
}
}
}
}
}
What is the syntax for multidimensional array in Swift?
Yes, there is nothing built-in (as far as I know). You can define a custom class/struct (as in Most efficient way to access multi-dimensional arrays in Swift?
or How to Declare a Multidimensional Boolean array in Swift?) with a subscript operator, so that a[0,0] = 1
works.
Here is a mixture of those solutions, but as a
generic struct
instead of class
. I have also changed the order of
the rows and columns parameters because I find that more natural:
struct Array2D<T : IntegerLiteralConvertible > {
let rows : Int
let cols : Int
var matrix: [T]
init(rows : Int, cols : Int) {
self.rows = rows
self.cols = cols
matrix = Array(count : rows * cols, repeatedValue : 0)
}
subscript(row : Int, col : Int) -> T {
get { return matrix[cols * row + col] }
set { matrix[cols*row+col] = newValue }
}
}
I don't see how to create such a thing from a literal like [2, 3 ;; -1, 0]
. But you could initialize it from a nested array:
extension Array2D {
init(_ elements: [[T]]) {
let rows = elements.count
let cols = elements[0].count
self.init(rows: rows, cols: cols)
for i in 0 ..< rows {
assert(elements[i].count == cols, "Array must have same number of elements for each row")
self.matrix.replaceRange(cols * i ..< cols * (i+1), with: elements[i])
}
}
}
Example:
let array = Array2D([[1, 2, 3], [4, 5, 6]])
println(array.rows) // 2
println(array.cols) // 3
println(array[1, 2]) // 6
println(array[1, 0]) // 4
You can additionally implement the ArrayLiteralConvertible
protocol to initialize a 2d array from a nested array literal:
extension Array2D : ArrayLiteralConvertible {
init(arrayLiteral elements: [T]...) {
self.init(elements)
}
}
Example:
let array : Array2D = [[1, 2, 3], [4, 5, 6]]
For square arrays (rows == columns
) you could alternatively initialize it from a plain array:
extension Array2D {
init(_ elements: [T]) {
let rows = Int(sqrt(Double(elements.count)))
assert(rows * rows == elements.count, "Number of array elements must be a square")
self.init(rows: rows, cols: rows)
self.matrix = elements
}
}
Example:
let squareArray = Array2D([2, 3, -1, 0])
println(squareArray.rows) // 2
println(squareArray.cols) // 3
println(squareArray[1, 0]) // -1
Creating multi-dimensional arrays containing different types in Swift
You have stored tuple value inside array. so, access the contents of a tuple by providing the index position .
subPurchaseDate = itemList[0][1].0 // for string value
subPurchaseDate = itemList[0][1].1 // for date
subPurchaseDate = itemList[0][1].2 // for Double
subPurchaseDate = itemList[0][1].3 // for Int
You can also access using it's named value.
var itemList: [[(stringValue: String, dateVal: Date, doubleValue: Double, intValue: Int)]] = []
// append elements in `itemList`
itemList.append([(stringValue: itemID, dateVal: purchase_date, doubleValue: purchase_date_ms, intValue: quantity)])
// access using it's named value
subPurchaseDate = itemList[0][1].stringValue // for string value
subPurchaseDate = itemList[0][1].dateVal // for date
subPurchaseDate = itemList[0][1].doubleValue // for Double
subPurchaseDate = itemList[0][1].intValue // for Int
Multidimensional arrays in Swift
For future readers, here is an elegant solution(5x5):
var matrix = [[Int]](repeating: [Int](repeating: 0, count: 5), count: 5)
and a dynamic approach:
var matrix = [[Int]]() // creates an empty matrix
var row = [Int]() // fill this row
matrix.append(row) // add this row
In Swift 5, how do I efficiently extract and use elements in multidimensional arrays?
You can create your own struct, something like this:
enum AmPm {
case am, pm
}
struct TimeMessage {
var ampm: AmPm
var hourStart: Int
var minuteStart: Int
var hourEnd: Int
var minuteEnd: Int
var message: String
}
With some convenience methods and properties:
extension TimeMessage {
init(_ ampm: AmPm, _ hourStart: Int, _ minuteStart: Int, _ hourEnd: Int, _ minuteEnd: Int, _ message: String) {
self.ampm = ampm
self.hourStart = hourStart
self.minuteStart = minuteStart
self.hourEnd = hourEnd
self.minuteEnd = minuteEnd
self.message = message
}
}
extension TimeMessage {
var hourStart24: Int {
switch ampm {
case .am:
return hourStart
case .pm:
return hourStart + 12
}
}
var hourEnd24: Int {
switch ampm {
case .am:
return hourEnd
case .pm:
return hourEnd + 12
}
}
}
extension TimeMessage {
func matches(_ date: Date) -> Bool {
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
return (hourStart24, minuteStart) <= (hour, minute)
&& (hour, minute) <= (hourEnd24, minuteEnd)
}
}
Using the above struct, you can declare your messageArray
as:
let messageArray: [TimeMessage] = [
TimeMessage(.am, 00, 00, 00, 01, "it's \nmidnight"),
TimeMessage(.am, 00, 02, 02, 59, "it's very late (or early), \nto be up"),
TimeMessage(.am, 03, 00, 03, 01, "are you ready \nfor the 03 am call?"),
TimeMessage(.am, 03, 02, 03, 59, "go to sleep \ni'll let you know when it's \n4"),
//...
]
And use it as:
let now = Date()
if let timeMessage = messageArray.first(where: {$0.matches(now)}) {
print(timeMessage.message)
} else {
print("No match")
}
Populate a multidimensional array with a loop
Calling array[i][j]
is for elements that are already there. You cannot use it to initialize the array, because currently it is just an empty array. You should be using .append
instead. Keep in mind that this actually isn't a multi-dimensional array like Rob Napier states, but it accomplishes the same goal in this scenario. Try something like this:
var array = [[Int]]()
for i in 0...3 {
var subArray = [Int]()
for j in 0...3 {
subArray.append(i + j)
}
array.append(subArray)
}
This prints:
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
Again, may not be the best approach, but this is just how you could do it in Swift.
Two-dimensional array in Swift
Define mutable array
// 2 dimensional array of arrays of Ints
var arr = [[Int]]()
OR:
// 2 dimensional array of arrays of Ints
var arr: [[Int]] = []
OR if you need an array of predefined size (as mentioned by @0x7fffffff in comments):
// 2 dimensional array of arrays of Ints set to 0. Arrays size is 10x5
var arr = Array(count: 3, repeatedValue: Array(count: 2, repeatedValue: 0))
// ...and for Swift 3+:
var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)
Change element at position
arr[0][1] = 18
OR
let myVar = 18
arr[0][1] = myVar
Change sub array
arr[1] = [123, 456, 789]
OR
arr[0] += 234
OR
arr[0] += [345, 678]
If you had 3x2 array of 0(zeros) before these changes, now you have:
[
[0, 0, 234, 345, 678], // 5 elements!
[123, 456, 789],
[0, 0]
]
So be aware that sub arrays are mutable and you can redefine initial array that represented matrix.
Examine size/bounds before access
let a = 0
let b = 1
if arr.count > a && arr[a].count > b {
println(arr[a][b])
}
Remarks:
Same markup rules for 3 and N dimensional arrays.
Related Topics
Swiftui: How to Make a Button Open a Url in Safari
Using Applescript with Apple Events in MACos - Script Not Working
Swift Realm Property '*' Has Been Added to Latest Object Model Migration
Swift Maximum Consecutive Positive Numbers
Array as a Dictionary Value in Swift Language
Swiftui Coordinator Not Updating the Containing View's Property
Swift [1,2] Conforms to Anyobject But [Enum.A, Enum.B] Does Not
Any Way to Chain == and || Operands
An Issue with Cashapelayer and Uibezierpath Drawing Circle Counterclockwise
How to Make Swiftui Listmenu with Different Behaviors
Xcode 6.3 Code Completion Too Slow
Swift Convert Time to Time Ago
Fastlane "Nokogiri Requires Ruby Version >= 2.3.0." Error