我有一个大数组,需要通过键(查找)访问它,所以我需要创建字典。 Swift 3.0 中有内置函数可以做到这一点,还是我需要自己编写?
首先,我将需要它用于具有键“String”的类,稍后我可能能够编写通用的模板版本(所有类型的数据和键)。
是这样吗(在 Swift 4 中)?
let dict = Dictionary(uniqueKeysWithValues: array.map{ ($0.key, $0) })
注: 正如评论中提到的,如果您有重复的键,使用
uniqueKeysWithValues
会产生致命错误 (Fatal error: Duplicate values for key: 'your_key':
)。
init(_:uniquingKeysWith:)
例如
let pairsWithDuplicateKeys = [("a", 1), ("b", 2), ("a", 3), ("b", 4)] // or `let pairsWithDuplicateKeys = array.map{ ($0.key, $0) }`
let firstValues = Dictionary(pairsWithDuplicateKeys, uniquingKeysWith: { (first, _) in first })
print(firstValues)
//prints ["a": 1, "b": 2]
let lastValues = Dictionary(pairsWithDuplicateKeys, uniquingKeysWith: { (_, last) in last })
print(lastValues)
//prints ["a": 3, "b": 4]
在 Swift 4 上,您可以通过使用 Dictionary's
grouping:by:
初始化器 来实现此目的
对于前: 您的课程名为 A
class A {
var name: String
init(name: String) {
self.name = name
}
// .
// .
// .
// other declations and implementions
}
接下来,您有一个类型为 A
的对象数组let a1 = A(name: "Joy")
let a2 = A(name: "Ben")
let a3 = A(name: "Boy")
let a4 = A(name: "Toy")
let a5 = A(name: "Tim")
let array = [a1, a2, a3, a4, a5]
假设您想通过按首字母对所有名称进行分组来创建字典。您可以使用 Swifts
Dictionary(grouping:by:)
来实现这一目标
let dictionary = Dictionary(grouping: array, by: { $0.name.first! })
// this will give you a dictionary
// ["J": [a1], "B": [a2, a3], "T": [a4, a5]]
但请注意,生成的 Dictionary “dictionary” 类型为
[String : [A]]
它不是类型
[String : A]
正如你所期望的那样。 (使用
#uniqueKeysWithValues
实现后者。)
我想你正在寻找这样的东西:
extension Array {
public func toDictionary<Key: Hashable>(with selectKey: (Element) -> Key) -> [Key:Element] {
var dict = [Key:Element]()
for element in self {
dict[selectKey(element)] = element
}
return dict
}
}
您现在可以执行以下操作:
struct Person {
var name: String
var surname: String
var identifier: String
}
let arr = [Person(name: "John", surname: "Doe", identifier: "JOD"),
Person(name: "Jane", surname: "Doe", identifier: "JAD")]
let dict = arr.toDictionary { $0.identifier }
print(dict) // Result: ["JAD": Person(name: "Jane", surname: "Doe", identifier: "JAD"), "JOD": Person(name: "John", surname: "Doe", identifier: "JOD")]
如果您希望代码更通用,您甚至可以在
Sequence
而不是 Array
上添加此扩展:
extension Sequence {
public func toDictionary<Key: Hashable>(with selectKey: (Iterator.Element) -> Key) -> [Key:Iterator.Element] {
var dict: [Key:Iterator.Element] = [:]
for element in self {
dict[selectKey(element)] = element
}
return dict
}
}
请注意,这会导致序列迭代,并且在某些情况下可能会产生副作用。
正如其他人已经说过的,我们需要了解哪些是关键。
但是,我正在尝试为我对你的问题的解释提供解决方案。
struct User {
let id: String
let firstName: String
let lastName: String
}
这里我假设不能存在 2 个具有相同
的用户id
let users: [User] = ...
let dict = users.reduce([String:User]()) { (result, user) -> [String:User] in
var result = result
result[user.id] = user
return result
}
现在
dict
是一本字典,其中 key
是 user id
,value
是 user value
。
要通过其
id
访问用户,您现在只需编写
let user = dict["123"]
给定给定类型
Element
的数组,以及确定 key
的 Element
的闭包,以下泛型函数将生成 Dictionary
类型的
[Key:Element]
func createIndex<Key, Element>(elms:[Element], extractKey:(Element) -> Key) -> [Key:Element] where Key : Hashable {
return elms.reduce([Key:Element]()) { (dict, elm) -> [Key:Element] in
var dict = dict
dict[extractKey(elm)] = elm
return dict
}
}
示例
let users: [User] = [
User(id: "a0", firstName: "a1", lastName: "a2"),
User(id: "b0", firstName: "b1", lastName: "b2"),
User(id: "c0", firstName: "c1", lastName: "c2")
]
let dict = createIndex(elms: users) { $0.id }
// ["b0": {id "b0", firstName "b1", lastName "b2"}, "c0": {id "c0", firstName "c1", lastName "c2"}, "a0": {id "a0", firstName "a1", lastName "a2"}]
正如 Martin R 所指出的,reduce 将为相关闭包的每次迭代创建一个新字典。这可能会导致巨大的内存消耗。
这是
createIndex
函数的另一个版本,其中空间要求为 O(n),其中 n 是榆树的长度。
func createIndex<Key, Element>(elms:[Element], extractKey:(Element) -> Key) -> [Key:Element] where Key : Hashable {
var dict = [Key:Element]()
for elm in elms {
dict[extractKey(elm)] = elm
}
return dict
}
let pills = ["12", "34", "45", "67"]
let kk = Dictionary(uniqueKeysWithValues: pills.map{ ($0, "number") })
["12": "number", "67": "number", "34": "number", "45": "number"]
斯威夫特5 斯威夫特4
以下将数组转换为字典。
let firstArray = [2,3,4,5,5]
let dict = Dictionary(firstArray.map { ($0, 1) } , uniquingKeysWith: +)
斯威夫特5
extension Array {
func toDictionary() -> [Int: Element] {
self.enumerated().reduce(into: [Int: Element]()) { $0[$1.offset] = $1.element }
}
}
此扩展适用于所有序列(包括数组),并允许您选择键和值:
extension Sequence {
public func toDictionary<K: Hashable, V>(_ selector: (Iterator.Element) throws -> (K, V)?) rethrows -> [K: V] {
var dict = [K: V]()
for element in self {
if let (key, value) = try selector(element) {
dict[key] = value
}
}
return dict
}
}
示例:
let nameLookup = persons.toDictionary{($0.name, $0)}
就简单地做吧
let items = URLComponents(string: "https://im.qq.com?q=13&id=23")!.queryItems!
var dic = [String: Any?]()
items.foreach {
dic[$0.name] = $0.value
}
reduce
不太合适,
let dic: [String: Any?] = items.reduce([:]) { (result: [String: Any?], item: URLQueryItem) -> [String: Any?] in
var r = result
r[item.name] = item.value // will create an copy of result!!!!!!
return r
}
据我从您的问题中了解到,您想将
Array
转换为 Dictionary
。
在我的例子中,我为
extension
创建 Array
,字典的键将是 Array
的索引。
示例:
var intArray = [2, 3, 5, 3, 2, 1]
extension Array where Element: Any {
var toDictionary: [Int:Element] {
var dictionary: [Int:Element] = [:]
for (index, element) in enumerate() {
dictionary[index] = element
}
return dictionary
}
}
let dic = intArray.toDictionary
兼容 Swift 5 标准库(Xcode 10.2+、iOS 12.2)。
这是初始化器的使用示例
init(uniqueKeysWithValues:)
输入
let array: [String] = Locale.isoRegionCodes
是由字符串表示的ISO31661-2代码的数组。
let countryCodeAndName: [String: String] = Dictionary(uniqueKeysWithValues: Locale.isoRegionCodes.map { ($0, Locale.current.localizedString(forRegionCode: $0) ?? "")} )
返回的字典,将列出以 ISO31661-2 代码作为键、以本地化区域名称作为值的所有区域。
输出:
...
"PL":"Poland"
"DE":"Germany"
"FR":"France"
"ES":"Spain"
...
示例2:
let dictionary: [String: String] = Dictionary(uniqueKeysWithValues: [ ("key1", "value1"), ("key2", "value2")] )
输出:
["key1": "value1", "key2": "value2"]
重要:
前提条件:序列不能有重复的key。
下面的代码将使应用程序崩溃:
let digitWords = ["one", "two", "three", "four", "five", "five"]
let wordToValue = Dictionary(uniqueKeysWithValues: zip(digitWords, 1...6))
与:
致命错误:键值重复:“五个”
如果你想遵循 map 设定的模式并快速减少,你可以做一些漂亮且实用的事情,如下所示:
extension Array {
func keyBy<Key: Hashable>(_ keyFor: (Element) -> Key) -> [Key: Element] {
var ret = [Key: Element]()
for item in self{
ret[keyFor(item)] = item
}
return ret
}
}
用途:
struct Dog {
let id: Int
}
let dogs = [Dog(id: 1), Dog(id: 2), Dog(id: 3), Dog(id: 4)]
let dogsById = dogs.keyBy({ $0.id })
// [4: Dog(id: 4), 1: Dog(id: 1), 3: Dog(id: 3), 2: Dog(id: 2)]
快捷方式:
extension Sequence {
func toDictionary<Key: Hashable>(with selectKey: (Element) -> Key) -> [Key: Element] {
reduce(into: [:]) { $0[selectKey($1)] = $1 }
}
}
// let arr = [Person(id: 1, name: "Alan")]
// arr.toDictionary { $0.id }
// ==
// [1: Person(id: 1, name: "Alan")]