【问题标题】:Using map on a Dictionary in Swift 2, to return a Dictionary在 Swift 2 中的 Dictionary 上使用 map 来返回 Dictionary
【发布时间】:2015-08-23 16:40:14
【问题描述】:

我无法弄清楚 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 的错误转圈。

【问题讨论】:

    标签: swift dictionary swift2


    【解决方案1】:

    原因是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))
    }
    

    记录器

    【讨论】:

    • 我遇到的问题是它是一种非功能性方法,而且首先是一个 Scala 程序员,它让我不寒而栗。有没有办法从地图返回Dictionary?我讨厌依靠副作用来实现我的目标的想法......! (我什至会选择返回一个数组,然后将其转换为字典......)
    • 来自手册:“映射返回一个数组,其中包含对自身进行映射变换的结果”。所以它返回一个数组,并且不能返回一个字典。我了解您担心副作用,但请考虑到 Swift 有一个非常 限制它们的好方法,有 varletstructclasses,此外,基本框架需要副作用,最初是用 C 和 Objective-C 编写的。所以如果你想继续用 Swift 和 iOS 编程,恐怕你必须熟悉非函数式编程技术。
    • 明白了——不过很遗憾,我曾希望 Swift 2 会“更实用”。尽管取得了长足的进步……每次迭代肯定会越来越近。我不希望 Swift 成为纯粹的函数式,但我确实希望看到这些功能不断发展。
    • 是的,我认为你是对的,而且 Swift2 越来越实用。好东西!
    【解决方案2】:
    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))) }
    

    【讨论】:

      【解决方案3】:

      @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,我们能够做到这一点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-07
        • 2019-03-22
        • 1970-01-01
        • 2023-03-15
        • 2015-09-19
        • 2012-03-01
        • 1970-01-01
        • 2016-06-04
        相关资源
        最近更新 更多