-1

This question has been asked and answered for a couple other coding languages, but I think I may have a unique problem anyway. So, I want to duplicate a three dimensional array (filled with arbitrary objects). I believe I found that this:

var duplicateArray = originalArray

Does not work, since, for whatever reason, they thought it would a nice safety measure to have this create a duplicate array, but filled with pointers as sub-arrays instead of duplicating the sub-arrays as well. This seems like a strange design choice, since if duplicateArray and originalArray were one-dimensional, this would work as intended. Anyway, so I tried this (where object is some arbitrary object):

var duplicateArray = [[[object]]]()
for x in 0..<originalArray.count {
    var tempArrYZ = [[object]]()
    for y in 0..<originalArray[x].count {
        var tempArrZ = [object]()
        for z in 0..<originalArray[x][y].count {
            let copiedObj = originalArray[x][y][z]
            tempArrZ.append(copiedObj)
        }
        tempArrYZ.append(tempArrZ)
    }
    duplicateArray.append(tempArrYZ)
}

This still does not work; all the values in duplicateArray will act like a pointer for their values in originalArray. Perhaps someone has a simple way of deeply duplicating multidimensional arrays, or perhaps someone can find my error?

EDIT: How is this a duplicate of that other question? I'm asking specifically how to "deeply" duplicate. The question that's being referred to nebulously asked about duplicating arrays.

user2252374
  • 153
  • 1
  • 6
  • Beware, initializing and appending to an array is expensive, as it could involve multiple resize operatations (which themselves require doing a full copy of the array). Initialize the array with the size you need, when you know it. – Alexander May 06 '16 at 22:09
  • 1
    Possible duplicate of [Swift - How do I make a exact duplicate copy of an array?](http://stackoverflow.com/questions/27812433/swift-how-do-i-make-a-exact-duplicate-copy-of-an-array) – Ryan May 06 '16 at 22:17
  • Yup, as pointed out, if values are value types, they get copied in the new array with `var duplicateArray = originalArray` If there are objects, their reference gets copied. Not sure a critique of swift is called for by someone who doesn't get that... – Daniel K May 06 '16 at 22:41

4 Answers4

0

I think it would be best to write an extension on Array that adds conformance to NSCopying, which recursively copies the elements. This solution would be very elegant because it could scale to any number of dimmensions.

Alexander
  • 59,041
  • 12
  • 98
  • 151
0
var duplicateArray = originalArray

Would work if the objects are not of reference type. However, for the reference type you need to actually create the copy of the object with copy. Your original code was pretty close.

var duplicateArray = [[[object]]]()
for x in 0..<originalArray.count {
    var tempArrYZ = [[object]]()
    for y in 0..<originalArray[x].count {
        var tempArrZ = [object]()
        for z in 0..<originalArray[x][y].count {
            let copiedObj = originalArray[x][y][z].copy()
            tempArrZ.append(copiedObj)
        }
        tempArrYZ.append(tempArrZ)
    }
    duplicateArray.append(tempArrYZ)
}
romants
  • 3,660
  • 1
  • 21
  • 33
0

As already stated, your problem isn't really the copying of the array, it's the copying of Objects. Arrays, like all structs, are copied by value. Objects are copied by reference.

When you copy an array of objects, it's a brand new array with brand new references to the contained objects. Your code is simply creating additional references to the same objects then organizing them in a similar fashion.

Anyway, here's my simpler/functional implementation for copying arrays:

func copyArrayWithObjects <T: Copying>(items: [T]) -> [T]{
    return items.map { $0.copy() }
}

func copy2DArrayWithObjects <T: Copying>(items: [[T]]) -> [[T]] {
    return items.map(copyObjectsInArray)
}

func copy3DArrayWithObjects<T: Copying>(items: [[[T]]]) -> [[[T]]] {
    return items.map(copy2DObjectInArray)
}

Then you can simply do this:

let copiedArray = copy3DArrayWithObjects(originalArray)

Theoretically I think it's possible to create a function to do this for an n-dimension array, but I haven't found a solution yet.

GetSwifty
  • 7,568
  • 1
  • 29
  • 46
-1

Swift arrays are value types so the snippet you provided is fine.

var duplicateArray = originalArray

See this example in a Playground as proof:

var array = [[["test"]]]
var newarray = array

// print different memory addresses

print(unsafeAddressOf(array[0][0][0])) // 0x00007ff7a302a760
print(unsafeAddressOf(newarray[0][0][0])) // 0x00007ff7a33000e0

If you use NSArray or reference types inside the Swift array, then they will no longer copy implicitly and will be treated with the same address - this can also be proved in the Playground. You would need to call copy() explicitly on reference types.

Tim
  • 8,932
  • 4
  • 43
  • 64
  • Strings in Swift are value types so they are always copied in such case https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html – romants May 06 '16 at 22:24
  • @RomanTsegelskyi I know Strings are value types. I explicitly state in my answer if you use reference types or an NSArray you won't copy. The author didn't mention if he was using reference or value types. I've added a small clarification, but not sure why there is a downvote. – Tim May 07 '16 at 08:30