从转换数组初始化字典

use*_*248 3 swift

有没有办法从数组中声明性地初始化字典是快速的?我正在寻找这样的东西:

struct MyStruct {

   var key: Int
   var value: String
}

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 1, value: "b")]
let dict = array.someTransform { // Some arguments
   // Some transformation
}
Run Code Online (Sandbox Code Playgroud)

dict[Int: String]什么类型的?

注意:我不是在寻找一个解决方案,forEach因为从这个任务的角度来看,它只是一个更复杂的for循环版本.

Ham*_*ish 13

Dictionary的序列初始化

在Swift 4中,假设密钥保证是唯一的,您可以简单地说:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 1, value: "b")]

let dict = Dictionary(uniqueKeysWithValues: array.lazy.map { ($0.key, $0.value) })

print(dict) // [0: "a", 1: "c"]
Run Code Online (Sandbox Code Playgroud)

这是使用SE-0165init(uniqueKeysWithValues:)初始化程序.它需要一系列键值元组,其中键保证是唯一的(如果不是,则会出现致命错误).所以在这种情况下,我们将懒惰变换应用于数组中的元素,以获得一组懒惰的键值对.

如果保证密钥唯一的,则需要某种方法来确定给定密钥使用哪些可能的值.为此,您可以使用同一提案中init(_:uniquingKeysWith:)初始化程序,并传递给定函数以确定在出现重复键时给定键使用哪个值.

uniquingKeysWith:函数的第一个参数是已经在字典中的值,第二个参数是尝试插入的值.

例如,这里我们每次在序列中出现重复键时都会覆盖该值:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 0, value: "b"),
             MyStruct(key: 1, value: "c")]

let keyValues = array.lazy.map { ($0.key, $0.value) }
let dict = Dictionary(keyValues, uniquingKeysWith: { _, latest in latest })

print(dict) // [0: "b", 1: "c"]
Run Code Online (Sandbox Code Playgroud)

要保留给定键的第一个值,并忽略同一个键的任何后续值,您需要一个uniquingKeysWith:闭包{ first, _ in first },[0: "a", 1: "c"]在这种情况下给出结果.


inout累加器减少

Swift 4中的另一个可能选项,假设您希望通过覆盖给定键每次出现时的值来合并任何重复键reduce(into:_:),将在SE-0171中引入.

reduce(_:_:)此不同,此方法inout在组合函数中使用累加器的参数.这允许它避免不必要地复制累加器,否则在reduce(_:_:)填充字典累加器时的每次迭代中都会发生这种复制.因此,这允许我们以线性而非二次时间填充它.

您可以像这样使用它:

let array = [MyStruct(key: 0, value: "a"), MyStruct(key: 0, value: "b"),
             MyStruct(key: 1, value: "c")]

let dict = array.reduce(into: [:]) { $0[$1.key] = $1.value }

print(dict) // [0: "b", 1: "c"]


// with initial capacity to avoid resizing upon populating.
let dict2 = array.reduce(into: Dictionary(minimumCapacity: array.count)) { dict, element in
    dict[element.key] = element.value
}

print(dict2) // [0: "b", 1: "c"]
Run Code Online (Sandbox Code Playgroud)