Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift字典默认值_Swift_Dictionary - Fatal编程技术网

Swift字典默认值

Swift字典默认值,swift,dictionary,Swift,Dictionary,我已经习惯于Python的defaultdicts的一种模式是一个字典,如果给定键的值没有被显式设置,它将返回一个默认值。在Swift中尝试这样做有点冗长 var dict = Dictionary<String, Array<Int>>() let key = "foo" var value: Array<Int>! = dict[key] if value == nil { value = Array<Int>() dict[k

我已经习惯于Python的defaultdicts的一种模式是一个字典,如果给定键的值没有被显式设置,它将返回一个默认值。在Swift中尝试这样做有点冗长

var dict = Dictionary<String, Array<Int>>()
let key = "foo"
var value: Array<Int>! = dict[key]
if value == nil {
    value = Array<Int>()
    dict[key] = value
}
var dict=Dictionary()
让key=“foo”
变量值:数组!=dict[键]
如果值==nil{
值=数组()
dict[键]=值
}
我意识到我可以创建一个这样做的类,但是实际的字典必须通过一个属性来访问,才能使用任何其他正常的字典方法

class DefaultDictionary<A: Hashable, B> {
    let defaultFunc: () -> B
    var dict = Dictionary<A, B>()

    init(defaultFunc: () -> B) {
        self.defaultFunc = defaultFunc
    }
    subscript(key: A) -> B {
        get {
            var value: B! = dict[key]
            if value == nil {
                value = defaultFunc()
                dict[key] = value
            }
            return value
        }
        set {
            dict[key] = newValue
        }
    }
}
classdefaultdictionary{
设defaultFunc:()->B
var dict=字典()
init(defaultFunc:()->B){
self.defaultFunc=defaultFunc
}
下标(键:A)->B{
得到{
变量值:B!=dict[键]
如果值==nil{
value=defaultFunc()
dict[键]=值
}
返回值
}
设置{
dict[key]=新值
}
}
}

有更好的模式吗?

除非我误解了Python中的defaultdict,否则我看不出nil合并怎么会不适合您。假设您有一个类型为
[Int:Int]
的字典,您希望它在默认情况下返回0。对于零合并,它看起来是这样的:

let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4] ?? 0
let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4, or: 0]
var dict = [2: 8, 3: 64, 1: 10]
dict[2, or: 0]++
dict // [2: 9, 3: 64, 1: 10]
dict[4, or: 0]++
dict // [2: 9, 3: 64, 1: 10, 4: 1]
var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}
你在评论中提到,这不起作用,因为它不会更新字典。不过,我不理解这个问题:如果知道nil的每个实例都将被默认值替换,那么为什么需要更新字典?也许我在这里遗漏了一些东西,但看起来违约和零合并(实际上)是一样的

:

在这种情况下,上面的例子可以这样写:

let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4] ?? 0
let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4, or: 0]
var dict = [2: 8, 3: 64, 1: 10]
dict[2, or: 0]++
dict // [2: 9, 3: 64, 1: 10]
dict[4, or: 0]++
dict // [2: 9, 3: 64, 1: 10, 4: 1]
var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}
在这种情况下,变异方法可以对键起作用,如下所示:

let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4] ?? 0
let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4, or: 0]
var dict = [2: 8, 3: 64, 1: 10]
dict[2, or: 0]++
dict // [2: 9, 3: 64, 1: 10]
dict[4, or: 0]++
dict // [2: 9, 3: 64, 1: 10, 4: 1]
var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}

使用Swift 2,您可以通过扩展
字典
,实现类似python版本的功能:

// Values which can provide a default instance
protocol Initializable {
    init()
}

extension Dictionary where Value: Initializable {
    // using key as external name to make it unambiguous from the standard subscript
    subscript(key key: Key) -> Value {
        mutating get { return self[key, or: Value()] }
        set { self[key] = newValue }
    }
}

// this can also be used in Swift 1.x
extension Dictionary {
    subscript(key: Key, or def: Value) -> Value {
        mutating get {
            return self[key] ?? {
                // assign default value if self[key] is nil
                self[key] = def
                return def
            }()
        }
        set { self[key] = newValue }
    }
}
类使用
??
后的闭包,因为它们不传播其值变异(仅“指针变异”;引用类型)

字典必须是可变的(
var
),才能使用这些下标:

// Make Int Initializable. Int() == 0
extension Int: Initializable {}

var dict = [Int: Int]()
dict[1, or: 0]++
dict[key: 2]++

// if Value is not Initializable
var dict = [Int: Double]()
dict[1, or: 0.0]

这在Swift 4中发生了变化,现在有一种方法可以读取密钥的值,或者在密钥不存在时提供默认值。例如:

let person = ["name": "Taylor", "city": "Nashville"]
let name = person["name", default: "Anonymous"]
这在修改字典值时特别有用,因为您可以编写如下代码:

let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4] ?? 0
let dict = [1:10, 2:8, 3:64]
let valueForKey = dict[4, or: 0]
var dict = [2: 8, 3: 64, 1: 10]
dict[2, or: 0]++
dict // [2: 9, 3: 64, 1: 10]
dict[4, or: 0]++
dict // [2: 9, 3: 64, 1: 10, 4: 1]
var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}

我在文章中介绍了这一变化和其他变化。

您可以使用nil合并运算符
,如下所示:
var-value:Array=dict[key]??[]
@ParamagneticCroissant将为变量分配所需的值,但不会更新字典然后写入
dict[key]=dict[key]??[]
,然后您可以强制展开
dict[key]
。难道您不能将
DefaultDictionary
作为
Dictionary
的子类并继承超类的所有方法吗?@martineau:Dictionary是一个结构,不能被子类化。如果
Value
类型,它就不起作用,因为引用类型不会将其突变传播给所有者。也许我不明白你的意思。是的,这基本上是一个语法问题。在python中,我可以说x=collections.defaultdict(list),然后执行x[“foo”].append(“bar”),而不必关心x[“foo”]是否已经初始化。每次都要重复默认值不是很方便。哦,好的。这是有道理的。是的,不幸的是,也许没有简单的方法来做你想要的事情。上面的方法可能是最“快速”的。@oisdk-see知道这一点很好,但它并不能完成同样的任务。使用类似defaultdict的方法,可以声明一次默认值,这很好。使用这种方法,似乎每次从字典中读取时都必须传递默认值。@alexp,虽然每次都必须传递默认值,
default
的参数声明为@autoclosure,这会在作为默认参数提供的语句周围创建隐式闭包,因此,确保仅在密钥不存在时对其进行计算/传递。因此,它更像是defaultdict,而不是最初实现的。