2015-08-23 36 views
11

sto avendo problemi a capire lo stile particolare di Swift 2 di map:usando la mappa su un dizionario in Swift 2, per restituire un dizionario

sto leggendo in un dizionario (da un file plist), così ho 've ottenuto un [String: AnyObject]:

let dictionary = NSDictionary(contentsOfFile: path) as? [String: AnyObject] 

Il mio obiettivo è quello di trasformare da un dizionario di Strings in un dizionario di istanze logger. Questo sarebbe [String: XCGLogger]:

let loggers = dictionary 
    .map { (n, l) in [ n: newLogger(l.0, withLevel: level(l.1)) ] } 

Tuttavia, questo restituisce un [[String: XCGLogger]] (che si presenta come una serie di dizionari per me). La domanda è come restituire un dizionario appiattito. Quando provo a utilizzare flatMap, ricomincio a girare intorno agli errori relativi alle chiusure o non riesco a chiamare flatMap su un tipo (Key, Value) -> NSDictionary.

risposta

8

Il motivo è che map può restituire solo matrici e non dizionari. Per ottenere un dizionario si dispone di diverse strategie, per esempio:

var loggers : [String: XCGLogger] = [:] 
dictionary.map{(n, l) in loggers[n] = newLogger(l.0, withLevel: level(l.1))} 

o forse:

var loggers : [String: XCGLogger] = [:] 
for (n, l) in dictionary { 
    loggers[n] = newLogger(l.0, withLevel: level(l.1)) 
} 

logger

+1

Il problema che ho con questo è che si tratta di un approccio non funzionale, ed essendo un programmatore Scala prima di tutto, mi dà i brividi. Non c'è modo di restituire un dizionario dalla mappa? Odio l'idea di fare affidamento su un effetto collaterale per raggiungere il mio obiettivo ...! (Potrei anche optare per la restituzione di un array e quindi la conversione in un dizionario ...) – Zac

+0

Dal manuale: "Mappa restituisce una matrice contenente i risultati della trasformazione della mappatura su se stessi". Quindi restituisce una matrice e non può restituire un dizionario. Capisco che tu abbia paura degli effetti collaterali, ma considera che Swift ha un * molto * buon modo per limitarli, con 'var' e' let', 'struct' e' classes' e, inoltre, che i framework di base richiedono effetto collaterale, essendo scritto originariamente in C e Objective-C. Quindi, se vuoi continuare a programmare in Swift e iOS, temo che tu debba familiarizzare con le tecniche di programmazione non funzionale. – Renzo

+0

Capito - un peccato, però, speravo che Swift 2 fosse "più funzionale". Buoni passi però ... decisamente avvicinandosi sempre di più ad ogni iterazione. Non mi aspetto che Swift sia puramente funzionale, ma mi piace veder evolvere queste funzionalità. – Zac

5
extension SequenceType { 
    func toDict<K : Hashable, V> 
    (@noescape convert: Generator.Element -> (K, V)) -> [K:V] { 
    var result: [K:V] = [:] 
    for x in self { 
     let (key, val) = convert(x) 
     result[key] = val 
    } 
    return result 
    } 
} 

dictionary.toDict { (n, l) in (n, newLogger(l.0, withLevel: level(l.1))) } 

O

extension Dictionary { 
    public init< 
    S : SequenceType where 
    S.Generator.Element == (Key, Value) 
    >(_ seq: S) { 
    self.init() 
    for (k, v) in seq { self[k] = v } 
    } 
} 

extension SequenceType { 
    func toDict<K : Hashable, V> 
    (@noescape convert: Generator.Element -> (K, V)) -> [K:V] { 
    return Dictionary(lazy(self).map(convert)) 
    } 
} 

dictionary.toDict { (n, l) in (n, newLogger(l.0, withLevel: level(l.1))) } 

O

extension Dictionary { 
    func map<K : Hashable, V>(@noescape transform: (Key, Value) -> (K, V)) -> [K:V] { 
    var result: [K:V] = [:] 
    for x in self { 
     let (key, val) = transform(x) 
     result[key] = val 
    } 
    return result 
    } 
} 

dictionary 
    .map { (n, l) in (n, newLogger(l.0, withLevel: level(l.1))) } 
1

modo leggermente più sintetica da @ risposta di Renzo sarebbe utilizzando ridurre:

let loggers: [String: XCGLogger] = dictionary.reduce([:]){(var loggers, kv) in 
loggers[kv.0] = newLogger(kv.1.0, withLevel: level(kv.1.1)) 
return loggers 
} 

sarebbe più conveniente e più chiaro se Swift potrebbe distruggere kv in (chiave, valore). Speriamo che la versione futura di Swift, saremo in grado di farlo.

Problemi correlati