0

I'm trying to figure out the best way in Swift to add values to an Array that is a Value in a Dictionary. I want to build a dictionary of contacts sorted by the first letter of their first name. For example [A : [Aaron, Adam, etc...], B : [Brian, Brittany, ect...], ...]

I found this function:

updateValue(_:forKey:)

And tried using it in a loop:

for contact in self.contacts.sorted() {
    self.contactDictionary.updateValue([contact], forKey: String(describing: contact.characters.first))           
}

But when I tried to use that it replaced the existing array with a new one. I know I can manually check to see if the key in the dictionary exists, if it does, retrieve the array and then append a new value, otherwise add the new key/value pair but I'm not sure if Swift provides an easier/better way to do this.

Any insight would be much appreciated!

2 Answers 2

3

You can use reduce(into:) method (Swift4) and as follow:

let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce(into: [String:[String]]()) { result, element in
    // make sure there is at least one letter in your string else return
    guard let first = element.first else { return }
    // create a string with that initial
    let initial = String(first)
    // initialize an array with one element or add another element to the existing value
    result[initial] = (result[initial] ?? []) + [element]
}
print(dictionary)   // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]

If you are using Swift3 or earlier you would need to create a mutable result dictionary inside the closure:

let contacts = ["Aaron", "Adam", "Brian", "Brittany", ""]
let dictionary = contacts.reduce([String:[String]]()) { result, element in
    var result = result
    guard let first = element.first else { return result }
    let initial = String(first)
    result[initial] = (result[initial] ?? []) + [element]
    return result 
}
print(dictionary)   // ["B": ["Brian", "Brittany"], "A": ["Aaron", "Adam"]]

Note that the result is not sorted. A dictionary is an unordered collection. If you need to sort your dictionary and return an array of (key, Value) tuples you can use sorted by key as follow:

let sorted = dictionary.sorted {$0.key < $1.key}
print(sorted)

"[(key: "A", value: ["Aaron", "Adam"]), (key: "B", value: ["Brian", "Brittany"])]\n"

Sign up to request clarification or add additional context in comments.

Comments

0

Swift 4's new dictionary initializers can do it all for you:

let contactInitials = contacts.filter{!$0.isEmpty}.map{ ($0.first!,[$0])  } 
let dict = [Character:[String]](contactInitials, uniquingKeysWith:+)

5 Comments

Yes but you don't need to access characters property anymore
True, old habits die hard.
And this requires all elements to have at least one character
Note that characters property it is already deprecated developer.apple.com/documentation/swift/string/…
To make it crash proof you can use flatMap let dict = [Character:[String]](contacts.flatMap{ $0.first == nil ? nil : ($0.first!,[$0]) }, uniquingKeysWith:+)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.