Swiftier Swift for 'add to array, or create if not there...'



我注意到Swift中的一个常见模式是

var x:[String:[Thing]] = [:]

所以,当您要"将项目添加到其中一个数组"时,您不仅可以

x[which].append(t)

您必须

if x.index(forKey: which) == nil {
    x[which] = []
    }
x[which]!.append(s!)

真的,是否有一种更快的方式来说

  x[index?!?!].append??(s?!)
  • 虽然这是关于样式的问题,但由于Swift的复制性质,
  • 性能似乎是一个关键问题

(请注意,显然您可以为此使用扩展名;这是关于迅速的问题。)

swift 4更新:

从Swift 4开始,字典具有subscript(_:default:)方法,因此

dict[key, default: []].append(newElement)

附加到已经存在的数组或空数组。示例:

var dict: [String: [Int]] = [:]
print(dict["foo"]) // nil
dict["foo", default: []].append(1)
print(dict["foo"]) // Optional([1])
dict["foo", default: []].append(2)
print(dict["foo"]) // Optional([1, 2])

swift 4.1 (当前在beta中)这也是 fast,在这里比较哈米什的评论。


swift< = 3:的先前答案,据我所知,没有办法"创建或更新"字典用单个下标调用值。

除了您写的内容外,您还可以使用nil-coalescing操作员

dict[key] = (dict[key] ?? []) + [elem]

或可选链接(如果附加操作,则返回nil可以执行不是):

if dict[key]?.append(elem) == nil {
     dict[key] = [elem]
}

如SE-0154中提到的制作数组的副本。

通过实施SE-0154,您将能够突变词典值而不制作副本:

if let i = dict.index(forKey: key) {
    dict.values[i].append(elem)
} else {
    dict[key] = [key]
}

目前,最有效的解决方案由Rob Napier给出在swift中的字典中,随着值的性能非常慢?如何正确优化或正确构造?:

var array = dict.removeValue(forKey: key) ?? []
array.append(elem)
dict[key] = array

一个简单的基准确认" Rob的方法"是最快的:

let numKeys = 1000
let numElements = 1000
do {
    var dict: [Int: [Int]] = [:]
    let start = Date()
    for key in 1...numKeys {
        for elem in 1...numElements {
            if dict.index(forKey: key) == nil {
                dict[key] = []
            }
            dict[key]!.append(elem)
        }
    }
    let end = Date()
    print("Your method:", end.timeIntervalSince(start))
}
do {
    var dict: [Int: [Int]] = [:]
    let start = Date()
    for key in 1...numKeys {
        for elem in 1...numElements {
            dict[key] = (dict[key] ?? []) + [elem]
        }
    }
    let end = Date()
    print("Nil coalescing:", end.timeIntervalSince(start))
}

do {
    var dict: [Int: [Int]] = [:]
    let start = Date()
    for key in 1...numKeys {
        for elem in 1...numElements {
            if dict[key]?.append(elem) == nil {
                dict[key] = [elem]
            }
        }
    }
    let end = Date()
    print("Optional chaining", end.timeIntervalSince(start))
}
do {
    var dict: [Int: [Int]] = [:]
    let start = Date()
    for key in 1...numKeys {
        for elem in 1...numElements {
            var array = dict.removeValue(forKey: key) ?? []
            array.append(elem)
            dict[key] = array
        }
    }
    let end = Date()
    print("Remove and add:", end.timeIntervalSince(start))
}

结果(在1.2 GHz Intel Core M5 MacBook上)适用于1000键/1000个元素:

您的方法:0.470084965229034零合并:0.460215032100677可选的链接0.397282958030701删除并添加:0.160293996334076

和1000键/10,000个元素:

您的方法:14.6810429692268零合并:15.1537700295448可选的链接14.4717089533806删除并添加:1.54668599367142

最新更新