当前位置: 首页 > 面试题库 >

Swiftier Swift,用于“添加到数组,如果不存在则创建…”

杨征
2023-03-14
问题内容

我注意到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中触摸数组时性能似乎是至关重要的问题

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


问题答案:

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版)开始,这也 _很快 比较Hamish的评论。

除了编写的内容外,您还可以使用nil-coalescing运算符

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

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

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

正如SE-0154在“提供字典键和值的自定义集合”中以及
@Hamish在注释中提到的那样,这两种方法均会复制数组。

使用SE-0154的实现,您将能够在不创建副本的情况下更改字典值:

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

目前,最有效的解决方案由Rob Napier在Swift中的Dictionary中使用MutableArray提供,因为值执行速度非常慢?如何优化或正确构建

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))
}

1000键/ 1000元素的结果(在1.2 GHz Intel Core m5 MacBook上):

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

对于1000个键/ 10,000个元素:

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


 类似资料:
  • 问题内容: 我很沮丧,我不知道该怎么做。 基本上,我只想创建一个表,但是如果它存在,则需要将其删除并重新创建,而不是将其截断,但是如果不存在,则可以创建它。 有人可以帮忙吗? 谢谢乔治 问题答案: 放在tablename您的发言之前。 该语句将删除该表(如果存在),但如果不存在则不会引发错误。

  • 这是我的代码: 每次执行程序时,我都会创建一个新文档,我只想在不存在的情况下创建它,如果文档存在,只需添加内容即可。

  • 问题内容: 我有一个钥匙型课。让我们称为map的实例。 我要添加{ ,}(是的一个实例,并且一)该地图。但是,如果键已经存在,我想求和该映射图中的当前值。 目前我使用 但是在Java 8中是否有一种时髦的方式来做到这一点,例如使用和? 遗憾的是我无法弄清楚。 谢谢。 问题答案: 这就是地图上的合并功能的作用。 这可以进一步减少到 它基本上等于

  • 问题内容: Python是否有任何内置功能可将数字添加到文件名(如果已存在)? 我的想法是,它将按某些OS的工作方式工作-如果将文件输出到已经存在该名称文件的目录中,则它将添加数字或对其进行递增。 即:如果“ file.pdf”存在,它将创建“ file2.pdf”,并下次创建“ file3.pdf”。 问题答案: 从某种意义上说,Python在模块中内置了此功能。不幸的是,您必须利用私有全局变量

  • 问题内容: 我的研究和实验还没有得到答案,所以我希望能有所帮助。 我正在修改一个应用程序的安装文件,该应用程序在以前的版本中没有我想立即添加的列。我不想手动添加列,而是要在安装文件中并且仅在表中不存在新列的情况下才添加。 该表如下创建: 如果我在create table语句下面添加以下内容,那么我不确定如果该列已经存在(可能已填充)会发生什么情况: 因此,我尝试了在某处找到的以下内容。这似乎不起作

  • 问题内容: 我正在使用PostgreSQL,并且是SQL的初学者。我正在尝试从查询创建表,并且如果运行: 它工作正常。但是然后如果我添加“如果不存在”并运行: 使用完全相同的查询,我得到: 有什么办法吗? 问题答案: CREATE TABLE AS被认为是与普通CREATE TABLE 分开的语句,并且 直到Postgres版本9.5 (请参阅changelog条目)不支持子句 为止 。(请务必查