AspiringDeveloper
AspiringDeveloper

Reputation: 153

Swift Reference to a Dictionary Key and Value Without Knowing Key

I have an Array of Dictionaries defined as

var users = [[String:String]]() 

The Dictionary inside the array is a simple username + yes/no flag [[1stUser: Y], [2ndUser: N], [3rdUser: N]]

In my TableView cell configuration, I defined

let userRecord = users[indexPath.row] as NSDictionary

and need to assign cell.textlabel.text = username (the key of the dictionary)

check flag (Y/N) and if Yes > cell.accessoryType = UITableViewCellAccessoryType.Checkmark

In the example above, I should get a checkmark next to 1stUser only.

The question is how to refer to the dictionary keys ('1stUser', '2nduser' etc.) without knowing them in advance and check values (Y/N)? All the Swift dictionary examples I have seen assume we know the actual key to retrieve its value (e.g users["1stUser"] does not help as I do not know in advance that 1stUser has a Y).

Upvotes: 4

Views: 4866

Answers (4)

Aaron Brager
Aaron Brager

Reputation: 66302

You should always know your dictionary keys. If you don't, you're structuring your data wrong - unknown data should always be in the value of a dictionary, never the key.

Consider instead using a dictionary with two keys: "username" and "flag".


Sample code:

var users = [[String:String]]()

users.append(["username" : "Aaron", "flag" : "yes"])
users.append(["username" : "AspiringDeveloper", "flag" : "yes"])

let userRecord = users[1]

let username = userRecord["username"]!
let flag = userRecord["flag"]!

Alternatively, you could build a basic class and avoid the dictionaries entirely:

class User {
    let username: String
    let flag: Bool

    init(username:String, flag:Bool) {
        self.username = username
        self.flag = flag
    }
}

var users = [User]()

users.append(User(username: "Aaron", flag: true))
users.append(User(username: "AspiringDeveloper", flag: true))

let userRecord = users[1]

let username = userRecord.username
let flag = userRecord.flag

Upvotes: 1

user1196549
user1196549

Reputation:

Without knowing the key(s) in advance, there is no other way than enumerating all (key, value) pairs (like @valfer said) and test the flag value. A dictionary will not support queries such as "report all entries having a True value".

Your problem statement is not clear about whether there is always exactly one True flag or not. If yes, you can stop the scan as soon as you found it.

Upvotes: 0

rintaro
rintaro

Reputation: 51911

I agree with @AaronBrager answer, but...

If you are sure the dictionary has at least one value, and no more than one value, you can

let dict = ["user1":"yes"]

// retrieve the key and the value
let (key, val) = dict[dict.startIndex] // -> key == "user1", val == "yes"

// retrieve the key
let key = dict.keys.first! // -> key == "user1"

So, let's convert [[String:String]] to [(name:String,flag:Bool)]

let users:[[String:String]] = [["1stUser": "Y"], ["2ndUser": "N"], ["3rdUser": "N"]]

let usersModified = users.map { dict -> (name:String, flag:Bool) in
    let (key, val) = dict[dict.startIndex]
    return (
        name: key,
        flag: val == "Y" ? true : false
    )
}

By doing that you can simply:

let user = usersModified[indexPath.row]
cell.textLabel.text = user.name
cell.accessoryType = user.flag ? .Checkmark : .None

Upvotes: 1

valfer
valfer

Reputation: 3545

You can iterate on a dictionary using:

for (key, value) in myDictionary {
   // here use key and value
}

Upvotes: 0

Related Questions