Swift等同于`[NSDictionary initWithObjects:forKeys:]`

时间:2016-01-21 14:57:30

标签: ios objective-c swift dictionary nsdictionary

Swift的本地Dictionary[NSDictionary initWithObjects: forKeys:]是否有相同的内容?

假设我有两个带键和值的数组,并希望将它们放在字典中。在Objective-C中,我这样做:

NSArray *keys = @[@"one", @"two", @"three"];
NSArray *values = @[@1, @2, @3];
NSDictionary *dict = [[NSDictionary alloc] initWithObjects: values forKeys: keys];

当然我可以通过两个数组迭代一个计数器,使用var dict: [String:Int]并逐步添加东西。但这似乎不是一个好的解决方案。使用zipenumerate可能是同时迭代这两者的更好方法。然而,这种方法意味着拥有一个可变的字典,而不是一个不可变的字典。

let keys = ["one", "two", "three"]
let values = [1, 2, 3]
// ???
let dict: [String:Int] = ["one":1, "two":2, "three":3] // expected result

5 个答案:

答案 0 :(得分:7)

Swift 4 开始,您可以直接从a创建字典 键/值对序列:

let keys = ["one", "two", "three"]
let values = [1, 2, 3]

let dict = Dictionary(uniqueKeysWithValues: zip(keys, values))

print(dict) // ["one": 1, "three": 3, "two": 2]

这假设所有键都不同,否则将中止 运行时异常。

如果不保证密钥不同,那么你可以

let keys = ["one", "two", "one"]
let values = [1, 2, 3]

let dict = Dictionary(zip(keys, values), uniquingKeysWith: { $1 })

print(dict) // ["one": 3, "two": 2]

第二个参数是一个闭包,它确定哪个值“胜出” 在重复密钥的情况下。

答案 1 :(得分:5)

您可以简单地使用Swift等效的initWithObjects:forKeys:

let keys = ["one", "two", "three"]
let values = [1, 2, 3]
var dict = NSDictionary.init(objects: values, forKeys: keys)

答案 2 :(得分:3)

使用结构工作纯Swift解决方案。使用zip迭代两个数组作为元组,然后为元组中的每个键值创建一个字典。

struct SomeStruct {
    var someVal: Int?
}

var keys = [String]()
var values = [SomeStruct]()

for index in 0...5 {
    keys.append(String(index))
    values.append(SomeStruct(someVal: index))
}

var dict = [String : Any]()

for (key, value) in zip(keys, values) {
    dict[key] = value
}

print(dict) // "["4": SomeStruct(someVal: Optional(4)), "2": SomeStruct(someVal: Optional(2)), "1": SomeStruct(someVal: Optional(1)), "5": SomeStruct(someVal: Optional(5)), "0": SomeStruct(someVal: Optional(0)), "3": SomeStruct(someVal: Optional(3))]"

您还可以在forEach上使用zip

var dict = [String : Any]()
zip(keys, values).forEach { dict[$0.0] = $0.1 }
print(dict) // "["4": SomeStruct(someVal: Optional(4)), "2": SomeStruct(someVal: Optional(2)), "1": SomeStruct(someVal: Optional(1)), "5": SomeStruct(someVal: Optional(5)), "0": SomeStruct(someVal: Optional(0)), "3": SomeStruct(someVal: Optional(3))]\n"

答案 3 :(得分:3)

单行,使用zipreduce

let dict = zip(keys, values).reduce([String:Int]()){ var d = $0; d[$1.0] = $1.1; return d }

您可以通过为reduce+定义Dictionary运算符来缩短tuple表达式:

func +<K,V>(lhs: [K:V], rhs: (K, V)) -> [K:V] {
    var result = lhs
    result[rhs.0] = rhs.1
    return result
}

let dict = zip(keys, values).reduce([String:Int](), combine: +)

答案 4 :(得分:1)

let keys = ["one", "two", "three"]
let values = [1, 2, 3]

func createDict<K:Hashable,V>(keys: [K], values:[V])->[K:V] {

    var dict: [K:V] = [:]

    // add validity checks here by yourself !
    // and return early, or throw an error ...

    keys.enumerate().forEach { (index,element) -> () in
        dict[element] = values[index]
    }
    return dict
}

let dict = createDict(keys, values: values)
// ["one": 1, "three": 3, "two": 2]

let dict2:[Int:Any] = createDict([1,2,3,4,5], values: [true,"two",3.4,5,[1,2,3]])
// [5: [1, 2, 3], 2: "two", 3: 3.4, 1: true, 4: 5]

与zip解决方案相比有什么区别? 很难说......对我来说,拉链类型注释是最大的问题

let a:Zip2Sequence<[Int],[Any]> = zip([1,2,3,4,5], [true,"two",3.4,5,[1,2,3]])
var d:[Int:Any] = [:]
a.forEach { (key, value) -> () in
    d[key] = value
}
print(d)
// [5: [1, 2, 3], 2: "two", 3: 3.4, 1: true, 4: 5]

但枚举解决方案也快一点