iOS*_*eek 60 arrays dictionary ios swift
我有一个Person对象的数组:
class Person {
let name:String
let position:Int
}
Run Code Online (Sandbox Code Playgroud)
而数组是:
let myArray = [p1,p1,p3]
Run Code Online (Sandbox Code Playgroud)
我想映射myArray成[position:name]经典解决方案的字典是:
var myDictionary = [Int:String]()
for person in myArray {
myDictionary[person.position] = person.name
}
Run Code Online (Sandbox Code Playgroud)
Swift是否有任何优雅的方式来实现功能性方法map,flatMap......或其他现代Swift风格
pos*_*sen 93
在Swift 4你可以使用它的into版本更干净,更有效地做@Tj3n的方法reduce它摆脱了临时字典和返回值,因此它更快更容易阅读.
struct Person {
let name: String
let position: Int
}
let myArray = [Person(name:"h", position: 0), Person(name:"b", position:4), Person(name:"c", position:2)]
let myDict = myArray.reduce(into: [Int: String]()) {
$0[$1.position] = $1.name
}
print(myDict)
Run Code Online (Sandbox Code Playgroud)
注意:在Swift 3中不起作用.
Tj3*_*j3n 87
好吧map不是一个很好的例子,因为它与循环相同,你可以使用reduce它,它将你的每个对象组合并变成单个值:
let myDictionary = myArray.reduce([Int: String]()) { (dict, person) -> [Int: String] in
var dict = dict
dict[person.position] = person.name
return dict
}
//[2: "b", 3: "c", 1: "a"]
Run Code Online (Sandbox Code Playgroud)
Mac*_*ser 72
从Swift 4开始,您可以轻松完成此操作.有两个 新的初始化器,它们从一系列元组(键和值对)构建字典.如果密钥保证是唯一的,您可以执行以下操作:
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 3)]
Dictionary(uniqueKeysWithValues: persons.map { ($0.position, $0.name) })
Run Code Online (Sandbox Code Playgroud)
=> [1: "Franz", 2: "Heinz", 3: "Hans"]
如果任何密钥重复,则会因运行时错误而失败.在这种情况下,您可以使用此版本:
let persons = [Person(name: "Franz", position: 1),
Person(name: "Heinz", position: 2),
Person(name: "Hans", position: 1)]
Dictionary(persons.map { ($0.position, $0.name) }) { _, last in last }
Run Code Online (Sandbox Code Playgroud)
=> [1: "Hans", 2: "Heinz"]
这表现为你的for循环.如果您不想"覆盖"值并坚持第一个映射,您可以使用:
Dictionary(persons.map { ($0.position, $0.name) }) { first, _ in first }
Run Code Online (Sandbox Code Playgroud)
=> [1: "Franz", 2: "Heinz"]
Swift 4.2添加了第三个初始化程序,它将序列元素分组到字典中.字典键由闭包派生.具有相同键的元素按照与序列中相同的顺序放入数组中.这使您可以获得与上面类似的结果.例如:
Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.last! }
Run Code Online (Sandbox Code Playgroud)
=> [1: Person(name: "Hans", position: 1), 2: Person(name: "Heinz", position: 2)]
Dictionary(grouping: persons, by: { $0.position }).mapValues { $0.first! }
Run Code Online (Sandbox Code Playgroud)
=> [1: Person(name: "Franz", position: 1), 2: Person(name: "Heinz", position: 2)]
您可以为Dictionary类型编写自定义初始值设定项,例如来自元组:
extension Dictionary {
public init(keyValuePairs: [(Key, Value)]) {
self.init()
for pair in keyValuePairs {
self[pair.0] = pair.1
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后map用于你的数组Person:
var myDictionary = Dictionary(keyValuePairs: myArray.map{($0.position, $0.name)})
Run Code Online (Sandbox Code Playgroud)
基于 KeyPath 的解决方案怎么样?
extension Array {
func dictionary<Key, Value>(withKey key: KeyPath<Element, Key>, value: KeyPath<Element, Value>) -> [Key: Value] {
return reduce(into: [:]) { dictionary, element in
let key = element[keyPath: key]
let value = element[keyPath: value]
dictionary[key] = value
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是你将如何使用它:
struct HTTPHeader {
let field: String, value: String
}
let headers = [
HTTPHeader(field: "Accept", value: "application/json"),
HTTPHeader(field: "User-Agent", value: "Safari"),
]
let allHTTPHeaderFields = headers.dictionary(withKey: \.field, value: \.value)
// allHTTPHeaderFields == ["Accept": "application/json", "User-Agent": "Safari"]
Run Code Online (Sandbox Code Playgroud)