Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: associative array with multiple keys:values

I am not expert in Swift and I have been using it for few months to build Mac Apps. I would like to represent in memory a data structure like that of PHP associative arrays but in Swift. Let's imagine that I have a table of data to load in memory with the following fields/records:

ID Surname Name
1  XXX     YYY
2  ZZZ     WWW
3  JJJ     KKK

What I would like to obtain is an associative array like the one I would be able to obtain in PHP:

$arr[1]["Surname"] = "XXX"
$arr[1]["Name"] = "YYY"
$arr[2]["Surname"] = "ZZZ"
$arr[2]["Name"] = "WWW"

I just cannot find the right data structure in Swift to obtain the same result. I tried with the following piece of code:

class resObject: NSObject {
    private var cvs = [Int: [String: String]]()

    override init() {

        self.cvs[0] = ["Name" : "XXX"]
        self.cvs[0] = ["Surname" : "YYY"]
        self.cvs[1] = ["Name" : "ZZZ"]
        self.cvs[1] = ["Surname" : "WWW"]

        for (key, arr) in cvs {
            let sur = arr["Surname"]
            let nam = arr["Name"]

            println("Row \(key) - Surname: \(sur), Name: \(nam)")
        }

        super.init()
    }
}

It looks to me pretty close, but it does not work. What I get in the output is the following (I don't care about the "Optional(s)":

Row 0 - Surname: Optional("XXX"), Name: nil
Row 1 - Surname: Optional("ZZZ"), Name: nil

I tried to make some tests in debug and I noticed that the data that are saved in memory are just that of the last key:value pair used (i.e. if I assign Surname first and Name second I get Surname as nil and Name with the correct value).

Please consider that, as in the example, I don't know the data structure when I declare the variable, so I declare it empty and fill it programmatically later.

I don't know if it is just me not declaring the data structure correctly, or if it is Swift that does not allow to do that. Any help will be greatly appreciated.

Thanks a lot. Regards, Alessio

like image 778
Alessio Avatar asked Jul 31 '15 00:07

Alessio


1 Answers

One way is a Dictionary of structs. Consider:

struct Person {
    var firstName: String
    var lastName: String
}

var peopleByID = [ Int: Person ]()
peopleByID[1] = Person(firstName: "First", lastName: "Last")
peopleByID[27] = Person(firstName: "Another", lastName: "LastName")

var myID = 1 // Try changing this to 2 later
if let p = peopleByID[myID] {
    println("Found: \(p.firstName) with ID: \(myID)")
}
else {
    println("No one found with ID: \(myID)")
}

You can then update the structure:

peopleByID[1].firstName = "XXX"
peopleByID[27].lastName = "ZZZ"

You can iterate freely:

for p in peopleByID.keys {
    println("Key: \(p) value: \(peopleByID[p]!.firstName)")
}

Note that a mere array of [Person] isn't so hot, because the IDs:

-- may not be Ints, but are often Strings

-- even if they remain Ints, an array takes up storage in proportion to the highest numbered index, whereas a Dictionary only takes up storage in proportion to the number of stored objects. Imagine storing just two ID's: 523123, and 2467411.

EDIT

It seems like you don't know the attributes ahead of time that will go into each Person object. That's odd, but you should then do:

struct Person {
    var attributes = [String : String]() // A dictionary of String keys and String values
}
var peopleByID = [ Int : Person ]()

// and then:

var p1 = Person()
var p2 = Person()
p1.attributes["Surname"] = "Somename"
p1.attributes["Name"] = "Firstname"
p2.attributes["Address"] = "123 Main St."
peopleByID[1] = p1
peopleByID[2] = p2

if let person1 = peopleByID[1] {
    println(person1.attributes["Surname"]!)

    for attrKey in person1.attributes.keys {
        println("Key: \(attrKey) value: \(person1.attributes[attrKey]!)")
    }
}
like image 83
BaseZen Avatar answered Nov 15 '22 01:11

BaseZen