extension of sequence

extension Sequence where Element: Hashable { //extension on sequence where element conforms to hashable protocol
    var frequencies: [Element: Int] { //dictionary of key element and value int
        return Dictionary(self.map{ ($0, 1)}, uniquingKeysWith: +) //creates new dictionary for key-value pairs in sequence and increments the value for duplicate keys
    }
}

Looking at line 3 here, is a new dictionary created and the key-value pairs are mapped to a value of 1 for every key-value pair as the keys are incremented?

Replies

No. But it is pretty hard to read this, even though the result is very easy to understand : counting the frequency in a sequence.


For readibility, it could be written in more extended form:

extension Sequence where Element: Hashable { //extension on sequence where element conforms to hashable protocol
    var frequencies: [Element: Int] { //dictionary of key element and value int
        return Dictionary(self.map{ ($0, 1)}, uniquingKeysWith: { $0 + $1}) //creates new dictionary for key-value pairs in sequence and increments the value for duplicate keys
    }
}

for example,

let res = ["a", "b", "c", "b", "d", "a", "a"].frequencies

yelds

["b": 2, "a": 3, "d": 1, "c": 1]


So, what it does,

map creates a dictionary from the sequence with pairs of the element of the sequence and 1

let res2 = ["a", "b", "c", "b", "d", "a", "a"].map{ ($0, 1)}

[("a", 1), ("b", 1), ("c", 1), ("b", 1), ("d", 1), ("a", 1), ("a", 1)]


From this, it creates the dictionary

("a", 1), ("b", 1), ("c", 1) starting with ["a": 1, "b": 1, "c":1]


When it meets an item with a duplicate key, such as ("b", 1), instead of trying to add a new item in dictionary (which would fail because key "b" already exists), iit modifies the value for the existing key ("b") by executing the closure which increments the value (of 1) by 1

then again, second ("a", 1) is not appended to the dictionary but the value for key "a" is modified from "a": 1 to "a":2.


This gives Dictionary(res2, uniquingKeysWith: +)

["b": 2, "a": 3, "d": 1, "c": 1]


Note : this is explained in documentation:

init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Dictionary.Value, Dictionary.Value) throws -> Dictionary.Value) rethrows where S : Sequence, S.Element == (Key, Value)

init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Dictionary.Value, Dictionary.Value) throws -> Dictionary.Value) rethrows where S : Sequence, S.Element == (Key, Value)


Creates a new dictionary from the key-value pairs in the given sequence, using a combining closure to determine the value for any duplicate keys.


Note 1: to simply create a dictionary from a sequence, you can use:

Dictionary(uniqueKeysWithValues: S), such as

Dictionary(uniqueKeysWithValues: [("d",1), ("e",2)])

which returns

["d": 1, "e": 2]


but if sequence has a duplicate key

[("d",1), ("e",2), ("d",3) ]

it fails with: Fatal error: Duplicate values for key: 'd' ; that's the interest of Dictionary(res2, uniquingKeysWith:) instead of crashing, it will update the value for the duplicating key according to the passed closure.


Note 2: you can play with the closure, for instance adding ten times the value ($1)

extension Sequence where Element: Hashable { //extension on sequence where element conforms to hashable protocol
    var frequencies: [Element: Int] { //dictionary of key element and value int
        return Dictionary(self.map{ ($0, 1)}, uniquingKeysWith: { $0 + 10*$1})
    }
}


returns:

["b": 11, "a": 21, "d": 1, "c": 1]


or multiply the current count ($0) by 10 each time a new occurrence is found

extension Sequence where Element: Hashable { //extension on sequence where element conforms to hashable protocol
    var frequencies: [Element: Int] { //dictionary of key element and value int
        return Dictionary(self.map{ ($0, 1)}, uniquingKeysWith: { 10*$0 + $1}) //creates new dictionary for key-value pairs in sequence and increments the value for duplicate keys
    }
}

returns:

["b": 11, "a": 111, "d": 1, "c": 1]


Edited (for fun), if you want to give stars

You could also write :

extension Sequence where Element: Hashable { //extension on sequence where element conforms to hashable protocol
    var frequencies: [Element: String] { //dictionary of key element and value int
        return Dictionary(self.map{ ($0, "✩")}, uniquingKeysWith: { $0 + $1 })


    }
}
let res = ["a", "b", "c", "b", "d", "a", "a"].frequencies
print(res)


and get

["b": "✩✩", "a": "✩✩✩", "d": "", "c": ""]

Are you ok now with this extension ?