Map array of objects to Dictionary in Swift

前端 未结 9 498
半阙折子戏
半阙折子戏 2021-01-30 00:32

I have an array of Person\'s objects:

class Person {
   let name:String
   let position:Int
}

and the array is:

         


        
相关标签:
9条回答
  • 2021-01-30 01:18

    You can use a reduce function. First I've created a designated initializer for Person class

    class Person {
      var name:String
      var position:Int
    
      init(_ n: String,_ p: Int) {
        name = n
        position = p
      }
    }
    

    Later, I've initialized an Array of values

    let myArray = [Person("Bill",1), 
                   Person("Steve", 2), 
                   Person("Woz", 3)]
    

    And finally, the dictionary variable has the result:

    let dictionary = myArray.reduce([Int: Person]()){
      (total, person) in
      var totalMutable = total
      totalMutable.updateValue(person, forKey: total.count)
      return totalMutable
    }
    
    0 讨论(0)
  • 2021-01-30 01:20

    Okay map is not a good example of this, because its just same as looping, you can use reduce instead, it took each of your object to combine and turn into single value:

    let myDictionary = myArray.reduce([Int: String]()) { (dict, person) -> [Int: String] in
        var dict = dict
        dict[person.position] = person.name
        return dict
    }
    
    //[2: "b", 3: "c", 1: "a"]
    

    In Swift 4 or higher please use the below answer for clearer syntax.

    0 讨论(0)
  • 2021-01-30 01:23

    Since Swift 4 you can do this very easily. There are two new initializers that build a dictionary from a sequence of tuples (pairs of key and value). If the keys are guaranteed to be unique, you can do the following:

    let persons = [Person(name: "Franz", position: 1),
                   Person(name: "Heinz", position: 2),
                   Person(name: "Hans", position: 3)]
    
    Dictionary(uniqueKeysWithValues: persons.map { ($0.position, $0.name) })
    

    => [1: "Franz", 2: "Heinz", 3: "Hans"]

    This will fail with a runtime error if any key is duplicated. In that case you can use this version:

    let persons = [Person(name: "Franz", position: 1),
                   Person(name: "Heinz", position: 2),
                   Person(name: "Hans", position: 1)]
    
    Dictionary(persons.map { ($0.position, $0.name) }) { _, last in last }
    

    => [1: "Hans", 2: "Heinz"]

    This behaves as your for loop. If you don't want to "overwrite" values and stick to the first mapping, you can use this:

    Dictionary(persons.map { ($0.position, $0.name) }) { first, _ in first }
    

    => [1: "Franz", 2: "Heinz"]

    Swift 4.2 adds a third initializer that groups sequence elements into a dictionary. Dictionary keys are derived by a closure. Elements with the same key are put into an array in the same order as in the sequence. This allows you to achieve similar results as above. For example:

    Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.last! }
    

    => [1: Person(name: "Hans", position: 1), 2: Person(name: "Heinz", position: 2)]

    Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.first! }
    

    => [1: Person(name: "Franz", position: 1), 2: Person(name: "Heinz", position: 2)]

    0 讨论(0)
提交回复
热议问题