官术网_书友最值得收藏!

Iterating, mapping, and reducing

Dictionaries are collections; literally, Dictionary conforms to the collection type. Therefore, it gains lots of the features of collections.

The element type of the [Key: Value] collection is a (Key, Value) tuple.

Let's take a look at the different syntax, as follows:

for (key, value) in swiftReleases {
print("\(key) -> \(value)")
}

// Output:
2016-09-13 -> Swift 3.0
2015-09-21 -> Swift 2.0
2017-09-19 -> Swift 4.0
2015-04-08 -> Swift 1.2
2014-09-09 -> Swift 1.0
2014-10-22 -> Swift 1.1
2018-03-29 -> Swift 4.1
As you can see, the order of keys is not preserved; this may affect your programs, if you expect the order to be consistent across runs. 
  • Using forEach: This is very similar to using the for in pattern:
swiftReleases.forEach { (key, value) in
print("\(key) -> \(value)")
}

Technically, you can pass any function or closure in the execution block, which can make your code clearer, by extracting the implementation of the iterator outside.

  • Using enumerated(): You can also get an enumerator from your dictionaries, if you need to get the index of the current key/value pair:
swiftReleases.enumerated().forEach { (offset, keyValue) in
let (key, value) = keyValue
print("[\(offset)] \(key) -> \(value)")
}

// Output:
[0] 2016-09-13 -> Swift 3.0
[1] 2015-09-21 -> Swift 2.0
[2] 2017-09-19 -> Swift 4.0
[3] 2015-04-08 -> Swift 1.2
[4] 2014-09-09 -> Swift 1.0
[5] 2014-10-22 -> Swift 1.1
[6] 2018-03-29 -> Swift 4.1
  • Mapping values: You can easily transform values from a dictionary to the same type, or to another type completely. This is done with the mapValues method. Our Swift releases dictionary is raw data, and we'll probably want to parse the version in a proper semantic versioning major, minor, patch tuple. First let's declare Version as typealiasas it's very simple, and it's unlikely that we'll need it to be struct or classat this point:
typealias Version = (major: Int, minor: Int, patch: Int)

Now, we need a simple method, which will transform a string version into a proper Version. Because not all strings are valid versions, we mark the method as throws, to encompass the cases where the string is invalid:

func parse(version value: String) throws -> Version {
// Parse the string 'Swift 1.0.1' -> (1, 0, 1)
fatalError("Provide implementation")
}

Finally, we'll apply the mapping to our dictionary object:

let releases: [String: Version] = try swiftReleases.mapValues { (value) -> Version in
try parse(version: value)
}

You can also use a shorter syntax, such as the following:

let releases = try swiftReleases.mapValues(parse(version:))

Or, you could use the following:

let releases = try swiftReleases.mapValues(parse)
  • Mapping keys with a reducer: Transforming values is very easy with the mapValues method, but Swift doesn't provide a mapKeys method to transform the keys into other types or use other values for them. This is where the reduce method comes into play. We can use a reducer to transform our releases into another dictionary of the type, [Date: Version], as follows:
let releases: [String: Version] = ... // the mapped values from previous examples
let
versionsByDate = try releases.reduce(into: [Date: Version]()) { (result, keyValue) in
let formatter = // NSDateFormatter...
if let date = formatter.date(from: keyValue.key) {
result[date] = keyValue.value
} else {
throw InvalidDateError()
}
}

assert(versionsByDate is [Date: Version])

We have now fully, and safely converted our original dictionary of strings into valid Swift objects, upon which we can perform more complex operations; these objects are more suited for handling in your programs. You will often find yourself transforming data from one type to another, so remember the map, reduce, and mapValues methods.

主站蜘蛛池模板: 绍兴市| 沙洋县| 秦皇岛市| 西乡县| 香格里拉县| 英超| 滁州市| 美姑县| 邻水| 剑阁县| 琼结县| 汨罗市| 永城市| 土默特右旗| 黑河市| 喜德县| 舞阳县| 新巴尔虎左旗| 荆州市| 前郭尔| 肥城市| 新邵县| 呼图壁县| 泸定县| 油尖旺区| 美姑县| 潼关县| 咸丰县| 大宁县| 清丰县| 盐亭县| 左云县| 北碚区| 平谷区| 繁昌县| 镇巴县| 当雄县| 郑州市| 营山县| 固阳县| 三台县|