2 Replies
      Latest reply on Jun 5, 2018 1:36 AM by Claude31
      MJHiOS Level 1 Level 1 (0 points)
        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?

        • Re: extension of sequence
          Claude31 Level 7 Level 7 (4,305 points)

          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": ""]