web-dev-qa-db-ja.com

Swift 2の辞書でマップを使用して、辞書を返す

Swift 2のmapの特定のスタイルを理解するのに問題があります:

私は(plistファイルから)辞書を読んでいるので、[String: AnyObject]を持っています:

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

私の目標は、Stringsの辞書からロガーインスタンスの辞書に変換することです。これは[String: XCGLogger]になります:

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

ただし、これは[[String: XCGLogger]]を返します(これは私には辞書の配列のように見えます)。問題は、フラット化された辞書をどのように返すかです。 flatMapを使おうとすると、クロージャーに関するエラーや、タイプ(Key, Value) -> NSDictionaryでflatMapを呼び出せないというエラーの周りで円を描いて走り始めます。

11
Zac

その理由は、mapは配列のみを返すことができ、辞書は返すことができないためです。辞書を取得するには、次のようないくつかの戦略があります。

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

多分:

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

ロガー

8
Renzo
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))) }

または

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))) }

または

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))) }
5
oisdk

@Renzoの答えからもう少し簡潔な方法は、reduceを使用することです。

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

Swiftがkvを(key、value)に破壊できれば、より便利で明確になります。Swiftの将来のバージョンで、これが可能になることを願っています。

1
hardboiledbaby