问题 在Swift 2中使用Dictionary上的map,返回一个Dictionary


我无法弄清楚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 我开始围绕关于闭包的错误或者无法在类型上调用flatMap (Key, Value) -> NSDictionary


8016
2017-08-23 16:40


起源



答案:


原因是 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
2017-08-23 17:08



我遇到的问题是它是一种非功能性方法,而且首先成为Scala程序员,它让我感到不安。有没有办法归还 Dictionary 来自地图?我讨厌依靠副作用实现目标的想法......! (我甚至选择返回一个数组,然后将其转换为字典......) - Zac
从手册:“Map返回一个包含映射转换结果的数组”。所以它返回一个Array,并且不能返回字典。我知道你害怕副作用,但考虑到Swift有一个 非常 用它来限制它们的好方法 var 和 let, struct 和 classes 而且,基本框架需要副作用,最初用C和Objective-C编写。因此,如果你想继续在Swift和iOS中编程,我恐怕你必须熟悉非函数式编程技术。 - Renzo
明白了 - 尽管如此,我曾希望Swift 2能够“更具功能性”。虽然很好,但每次迭代都越来越接近。我不认为Swift是纯功能的,但我确实希望看到这些功能发展。 - Zac
是的,我认为你是对的,Swift2越来越实用。好东西! - Renzo


答案:


原因是 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
2017-08-23 17:08



我遇到的问题是它是一种非功能性方法,而且首先成为Scala程序员,它让我感到不安。有没有办法归还 Dictionary 来自地图?我讨厌依靠副作用实现目标的想法......! (我甚至选择返回一个数组,然后将其转换为字典......) - Zac
从手册:“Map返回一个包含映射转换结果的数组”。所以它返回一个Array,并且不能返回字典。我知道你害怕副作用,但考虑到Swift有一个 非常 用它来限制它们的好方法 var 和 let, struct 和 classes 而且,基本框架需要副作用,最初用C和Objective-C编写。因此,如果你想继续在Swift和iOS中编程,我恐怕你必须熟悉非函数式编程技术。 - Renzo
明白了 - 尽管如此,我曾希望Swift 2能够“更具功能性”。虽然很好,但每次迭代都越来越接近。我不认为Swift是纯功能的,但我确实希望看到这些功能发展。 - Zac
是的,我认为你是对的,Swift2越来越实用。好东西! - 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
2017-08-23 20:57





@ 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
2017-12-12 05:54