Derry Derry - 3 years ago 92
Swift Question

How can I populate a dynamically sized 2D array in Swift 3.0 to be an X by 4 two-D array?

I want to write a function in Swift 3.0 that will populate a 2D array of string arrays, meaning something like {{"Mr.", "John", "Q.", "Public"} {"Ms.", "Jane", "E.", "Doe"}...}

In my program, the titles are in an array of their own, as are the first, while middle initial and last names are in their own arrays together.

So far, I have:

func build2DStringArray() -> [[String]]{
var col = 0
var row = 0
var string2DArray = [[String]]()

for title in titles{
string2DArray[col][row].append(title){
for firstname in firstNames{
string2DArray[col][row].append(firstname){
for lasttwo in lastTwo{
string2DArray[col][row].append(middleinit)
string2DArray[col][row].append(lastname)
col += 1
row += 1
}
}
}
}
}
return string2DArray
}


but when I run it, I get "index out of range." How can I get this to do what I need. As of now, I need to have 150 sets of 4 strings, altho I cannot hardcode those numbers. I've tried looking up the documentation and its very poor for this kind of thing. Hence why I come here.

Answer Source

One issue is that you're initializing the [[String]] but you also need to append a [String] for every column. Another issue is what happens if one of your arrays is longer than the rest?

Here's a way to do it with any number of [String]:

func zipIntoArray<T>(arrays: [T]...) -> [[T]] {
  var result = [[T]]()
  var index = 0
  while true {
    var current = [T]()
    for array in arrays {
      guard array.indices.contains(index) else { return result }
      current.append(array[index])
    }
    result.append(current)
    index += 1
  }
}

let a = ["one a", "two a", "three a", "four a"]
let b = ["one b", "two b", "three b"]
let c = ["one c", "two c", "three c"]
let d = ["one d", "two d", "three d"]

let big = zipIntoArray(arrays: a, b, c, d)

print(big)
// [["one a", "one b", "one c", "one d"], ["two a", "two b", "two c", "two d"], ["three a", "three b", "three c", "three d"]]

print(big[0][1])
// two b

When the function encounters the end of any of the arrays it immediately returns. In that way each row has the same number of elements.

This doesn't follow your addressing of "[col][row]" and instead would be used as "[row][col]" but I feel that's a minor detail, especially since the latter is a paradigm followed by many programmers. Rows tend to be a group of associated data and so each group is contained in a single array. Even better might be to do away with that array and instead use a struct with named properties.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download