arraysswiftdictionarybig-ocode-cleanup

Difference between creating a dictionary by reduce on an array vs by assigning each item on iteration


I came across a question on StackOverflow: Swift - Convert Array to Dictionary where the user wants to take the elements of an array and wants to put them in a dictionary and assign 0 to each of them. (Key as Players and value as their scores) So:

var playerNames = ["Harry", "Ron", "Hermione"]

becomes

var scoreBoard: [String:Int] = [ "Ron":0, "Harry":0, "Hermione":0 ]

This question got 2 answers: 1) Uses reduce on the array

let scoreboard = playerNames.reduce(into: [String: Int]()) { $0[$1] = 0 }

2)Creates a dictionary and iterates on array to add each value key pair to it

var dictionary = [String: Int]()
for player in playerNames {
    dictionary[player] = 0
}

I took the BenchTimer function from https://github.com/nyisztor/swift-algorithms to test both of these ways of solving. And they both seem to operate in O(n).

enter image description here

enter image description here

I was wondering why we would prefer the first one over the other since the person who wrote the second solution got a bad comment about their coding skills.

Edit: Some functionality gets deprecated by Apple in newer versions so isn't it better to stick with the basics and create our own ways to do things?

Thank you for the answers


Solution

  • Today, IMO, you shouldn't use either of these. We now have Dictionary.init(uniqueKeysWithValues:) and .init(_:uniquingKeysWith:) which much more clearly state their intent, and make corner cases, such as duplicate keys, explicit.

    If you statically can prove that all the keys are unique, then you would use the first one:

    let scoreboard = Dictionary(uniqueKeysWithValues: playerNames.map { (name: $0, score: 0) })
    

    If you cannot prove the keys are unique, you'd use the second one, which would allow you to explicitly decide what to do in cases of conflict.

    let scoreboard = Dictionary(playerNames.map { (name: $0, score: 0) },
                                uniquingKeysWith: { first, _ in first })
    

    Note how this approach allows labels to make clear what the key is and what the value is. I haven't benchmarked this code, but I would expect it to be very similar in terms of time to the others.