在这个例子中,我试图将每个值递增1.但是这是附带的例子 – 主要目的是弄清楚如何应用map()到字典。
var d = ["foo" : 1,"bar" : 2] d.map() { $0.1 += 1 }
map是SequenceType和CollectionType的扩展方法。它的定义如下:
func map<T>(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
如果我们删除一些杂乱,我们得到这个简化的定义:
func map<T>(transform: (Self.Generator.Element) -> T) -> [T]
由于Dictionary符合CollectionType,它的Element typealias是一个(键,值)元组,这意味着你应该能够这样做:
result = dict.map { (key,value) in (key,value.uppercaseString) }
但是,这不会实际分配到一个Dictionary类型的变量。 map方法被定义为总是返回一个数组([T]),即使对于像字典这样的其他类型。如果你写一个构造函数,将一个二元组的数组变成一个字典,所有将正确的世界:
extension Dictionary { init(_ pairs: [Element]) { self.init() for (k,v) in pairs { self[k] = v } } } result = Dictionary(dict.map { (key,value.uppercaseString) })
您甚至可能想编写一个特定于字典的版本的map,以避免显式调用构造函数。这里我还包括一个过滤器的实现:
extension Dictionary { func mapPairs<OutKey: Hashable,OutValue>(@noescape transform: Element throws -> (OutKey,OutValue)) rethrows -> [OutKey: OutValue] { return Dictionary<OutKey,OutValue>(try map(transform)) } func filterPairs(@noescape includeElement: Element throws -> Bool) rethrows -> [Key: Value] { return Dictionary(try filter(includeElement)) } }
我使用不同的名称,因为否则只有返回值将区分这两个方法,这可能使代码非常模糊。
使用它像这样:
result = dict.mapPairs { (key,value.uppercaseString) }
顺便说一句,为了许多目的,你可能只想映射值:
extension Dictionary { func map<OutValue>(@noescape transform: Value throws -> OutValue) rethrows -> [Key: OutValue] { return Dictionary<Key,OutValue>(try map { (k,v) in (k,try transform(v)) }) } }
原因是如果两个最终映射到同一个键,mapPairs可能丢失对。另一方面,map(Value – > OutValue)总是保留键,所以这不是危险。
Swift 3怎么样?
Swift Evolution提议SE-0100将添加到Swift 3一个更复杂的版本的我的Dictionary.init(_ :)初始化;它将支持从任何兼容的序列初始化一个字典,如果任何键冲突,返回nil。它还包括一个更复杂的版本,它允许您选择如何处理冲突的键;这将让你(例如)忽略,连接,求和或选择最大或最小值。核心团队已同意对SE-0100进行公开审核,但尚未安排。
每个Swift提案都经过一个为期一周的公共审核期,在此期间,您可以将您对该提案的意见发送给Swift核心团队,以帮助他们做出决定。如果您已经从阅读这篇文章中获益,您的经验可能是相关的。您可以通过订阅swift-evolution-announce列表了解SE-0100审查和所有其他Swift Evolution提案审核的时间。审核开始后,您可以通过电子邮件将评论私下发送给审核经理。
mapValues方法(像我的Dictionary.map(transform:Value – > OutValue) – > [Key:OutValue]方法)已经讨论了几次,但还没有正式提出。