Search code examples
swiftdictionarymetatype

What is the best way in Swift 4+ to store a set of homogenous arrays for various types in a dictionary?


Consider a situation where we want to have a dictionary of arrays, with each array being a homogeneous collection of values of some type (which may be a struct or a primitive type). I'm currently using the ObjectIdentifier of the type defining it thusly:

let pInts : [UInt32] = [4, 6, 99, 1001, 2032]
let pFloats : [Float] = [3.14159, 8.9]
let pBools : [Bool] = [true, false, true]

let myDataStructure : [ObjectIdentifier : [Any]] = [
   ObjectIdentifier(Float.self) : pFloats,
   ObjectIdentifier(UInt32.self) : pInts,
   ObjectIdentifier(Bool.self) : pBools
]

The issue here is that when traversing the data structure, Swift doesn't know that the objects in each list are homogeneous. Since swift is statically typed, I'm guessing it is not possible to typecast the [Any] lists using the ObjectIdentifier keys. Consider this traversal pseudocode:

for (typeObjId, listOfValuesOfSometype) in myDataStructure {
   // do something like swap values around in the array,
   // knowing they are homogeneously but anonymously typed
}

So, is there some metatype machinery I can concoct to represent this data structure in a way that does not anticipate the list of actual types that will have arrays in it?


Solution

  • I'm not exactly sure what you want to accomplish, Inside the dictionary loop the arrays will always be of type Any, but if you want to move items in the arrays around, you could just do that. Just reassign the array first to a var and then put it back in the dictionary.

    If you do want to loop through the items of a specific type, then you could use the array helper function below.

    func testX() {
        let pInts: [UInt32] = [4, 6, 99, 1001, 2032]
        let pFloats: [Float] = [3.14159, 8.9]
        let pBools: [Bool] = [true, false, true]
    
        var myDataStructure: [ObjectIdentifier: [Any]] = [
            ObjectIdentifier(Float.self): pFloats,
            ObjectIdentifier(UInt32.self): pInts,
            ObjectIdentifier(Bool.self): pBools
        ]
    
        // Swap the first 2 items of every array
        for d in myDataStructure {
            var i = d.value
            if i.count > 1 {
                let s = i[0]
                i[0] = i[1]
                i[1] = s
            }
            myDataStructure[d.key] = i
        }
    
        // Now dump all data per specific type using the array helper function.
        for i: UInt32 in array(myDataStructure) {
            print(i)
        }
        for i: Float in array(myDataStructure) {
            print(i)
        }
        for i: Bool in array(myDataStructure) {
            print(i)
        }
    }
    
    func array<T>(_ data: [ObjectIdentifier: [Any]]) -> [T] {
        return data[ObjectIdentifier(T.self)] as? [T] ?? []
    }