2016-07-19 9 views
12

Ho un array di oggetti 's Person:Mappa array di oggetti al dizionario a Swift

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

e l'array è:

let myArray = [p1,p1,p3] 

voglio mappare myArray essere un dizionario di [position:name] la soluzione classica è:

var myDictionary = [Int:String]() 

for person in myArray { 
    myDictionary[person.position] = person.name 
} 

c'è un modo elegante B y Swift per farlo con l'approccio funzionale map, flatMap ... o altro stile moderno Swift

+0

Il tuo modo classico è molto meglio in termini di prestazioni – AamirR

risposta

28

Va bene map non è un buon esempio di questo, perché il suo solo stesso di loop, è possibile u SE reduce invece, ha preso ogni del vostro oggetto di combinare e trasformare in unico valore:

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"] 
+0

Questo è il metodo stavo pensando. – Fogmeister

+1

Mi piace questo approccio ma è più efficiente della semplice creazione di un ciclo per caricare un dizionario? Mi preoccupo delle prestazioni perché sembra che per ogni oggetto debba creare una nuova copia mutabile di un dizionario sempre più grande ... –

+0

in realtà è un loop, in questo modo è un modo semplificato di scriverlo, le prestazioni sono le stesse o in qualche modo migliori del normale loop – Tj3n

4

Si può scrivere inizializzatore personalizzato per Dictionary tipo, per esempio da tuple:

extension Dictionary { 
    public init(keyValuePairs: [(Key, Value)]) { 
     self.init() 
     for pair in keyValuePairs { 
      self[pair.0] = pair.1 
     } 
    } 
} 

e quindi utilizzare map per la matrice di Person:

var myDictionary = Dictionary(keyValuePairs: myArray.map{($0.position, $0.name)}) 
1

è possibile utilizzare una funzione di ridurre. In primo luogo ho creato un inizializzatore designato per la classe Person

class Person { 
    var name:String 
    var position:Int 

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

Più tardi, ho inizializzato un array di valori

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

E, infine, la variabile dizionario ha il risultato:

let dictionary = myArray.reduce([Int: Person]()){ 
    (total, person) in 
    var totalMutable = total 
    totalMutable.updateValue(person, forKey: total.count) 
    return totalMutable 
} 
15

In Swift 4 puoi fare l'approccio di @ Tj3n in modo più pulito ed efficiente utilizzando la versione into di reduce Elimina il temporaneo dictio nary e il valore restituito in modo che sia più veloce e più facile da leggere.

struct Person { 
    let name: String 
    let position: Int 
} 
let myArray = [Person(name:"h", position: 0), Person(name:"b", position:4), Person(name:"c", position:2)] 
let myDict = myArray.reduce(into: [Int: String]()) { 
    $0[$1.position] = $1.name 
} 
print(myDict) 

Nota: non funziona in Swift 3.