Swift 3:数组到字典?

Pet*_*r71 35 arrays dictionary filter swift

我有一个大型数组,需要通过键(查找)访问它,所以我需要创建字典.在Swift 3.0中是否有内置函数可以这样做,还是我需要自己编写?

首先,我将需要它用于具有键"String"的类,稍后我可以编写用于通用目的的模板版本(所有类型的数据和键).

Kam*_*com 68

是这样的(在Swift 4中)?

let dict = Dictionary(uniqueKeysWithValues: array.map{ ($0.key, $0) })
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.谢谢 (4认同)
  • 您应该使用“.lazy.map”来防止中间复制和数组分配。 (2认同)

ove*_*tor 41

我想你正在寻找这样的东西:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

你现在可以这样做:

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")]
Run Code Online (Sandbox Code Playgroud)

如果您希望代码更通用,您甚至可以添加此扩展名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
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这会导致序列被迭代,并且在某些情况下可能会产生副作用.


Bur*_*ala 39

在Swift 4上,您可以使用Dictionary的 grouping:by:初始化程序实现此目的

例如:你有一个名为A的班级

class A {

    var name: String

    init(name: String) {
        self.name = name
    }
    // .
    // .
    // .
    // other declations and implementions
}
Run Code Online (Sandbox Code Playgroud)

接下来,您有一个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]
Run Code Online (Sandbox Code Playgroud)

假设您要通过将所有名称按其第一个字母分组来创建字典.您使用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]] 
Run Code Online (Sandbox Code Playgroud)

资源

  • 这是最好和正确的答案.所有其他答案都忽略了这一点.当然,可以迭代数组并将值复制到字典中.重点是使用_functioal_构造来做到这一点,它可能具有懒惰的额外好处. (8认同)

Luc*_*tti 11

正如其他人已经说过的那样,我们需要了解哪些是关键.

但是,我试图为我对你的问题的解释提供一个解决方案.

struct User {
    let id: String
    let firstName: String
    let lastName: String
}
Run Code Online (Sandbox Code Playgroud)

在这里,我假设有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
}
Run Code Online (Sandbox Code Playgroud)

现在dict是一本字典,其中keyuser idvalueuser value.

要通过它访问用户,id您现在可以简单地写

let user = dict["123"]
Run Code Online (Sandbox Code Playgroud)

更新#1:一般方法

给定一个给定类型的阵列Element,和封闭该确定keyElement,下面的通用函数将生成一个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
    }
}
Run Code Online (Sandbox Code Playgroud)

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"}]
Run Code Online (Sandbox Code Playgroud)

更新#2

正如Martin R所指出的,reduce将为相关闭包的每次迭代创建一个新的字典.这可能会导致巨大的内存消耗.

这是createIndex函数的另一个版本,其中空间要求是O(n),其中n是elms的长度.

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
}
Run Code Online (Sandbox Code Playgroud)


use*_*er_ 7

雨燕5

extension Array {

    func toDictionary() -> [Int: Element] {
        self.enumerated().reduce(into: [Int: Element]()) { $0[$1.offset] = $1.element }
    }
    
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*dan 6

let pills = ["12", "34", "45", "67"]
let kk = Dictionary(uniqueKeysWithValues: pills.map{ ($0, "number") })

["12": "number", "67": "number", "34": "number", "45": "number"]
Run Code Online (Sandbox Code Playgroud)

swift5 swift4


Joh*_*ohn 5

此扩展适用于所有序列(包括数组),并允许您选择key 和 value

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
    }
}
Run Code Online (Sandbox Code Playgroud)

例子:

let nameLookup = persons.toDictionary{($0.name, $0)}
Run Code Online (Sandbox Code Playgroud)


cas*_*las 5

以下将数组转换为字典。

let firstArray = [2,3,4,5,5] 

let dict = Dictionary(firstArray.map { ($0, 1) } , uniquingKeysWith: +)
Run Code Online (Sandbox Code Playgroud)