【问题标题】:How can I add values to an array stored in a map?如何向存储在地图中的数组添加值?
【发布时间】:2017-01-10 12:27:46
【问题描述】:

假设我有一个键到值数组的映射,并且想要将一个值添加到这些数组之一:

func addVal<K:Hashable, V>(map: inout [K: [V]], new: (key: K, val: V)) {
    if var list = map[new.key] {
        list.append(new.val)
    } else {
        map[new.key] = [new.val]
    }
}

此代码不起作用:由于数组具有值语义,listmap[new.key] 的副本,并且新值永远不会插入到存储的数组中。

有没有一种很好的惯用方法?

我知道这非常有效:

func addVal<K:Hashable, V>(map: inout [K: [V]], new: (key: K, val: V)) {
    if map[new.key] != nil {
        map[new.key].append(new.val)
    } else {
        map[new.key] = [new.val]
    }
}

不过,我认为这是一个不太好的解决方法;我宁愿处理选项而不明确检查nil

【问题讨论】:

标签: arrays swift data-structures hashmap


【解决方案1】:

这是安全的,不会摆弄nil,并避免不必要地复制操作数组:

func addVal<K:Hashable, V>(map: inout [K: [V]], new: (key: K, val: V)) {
    if let _ = map[new.key] {
        map[new.key]!.append(new.val) 
    } else {
        map[new.key] = [new.val]
    }
}

【讨论】:

  • 请注意,我相信这仍然会导致变异数组的副本,因为map[new.key]!.append(new.val) 将创建数组的临时变量(现在字典和临时变量都可以查看数组),附加到该数组(导致写入时复制),然后将其插入回字典中。请参阅我上面链接的问答,以了解避免这种复制的方法。
  • @Hamish 如果不直接编辑通过函数传递的对象,这是否可以避免?似乎所有 inout 变量都是这种情况。
  • @BenjaminLowry 好吧,通过获取数组的唯一视图可以避免这种情况,如果不暂时删除字典的视图(即从字典中删除,然后重新添加),你就无法做到这一点。但在大多数情况下,这个成本应该比复制数组便宜。 inout 参数在大多数情况下被视为传递引用,因此不会复制字典本身。
  • @Hamish 是否有任何深层原因,或者在这种情况下可以改进编译器以跳过复制?
  • @Raphael(我认为我不会比 Rob 对您对他帖子的评论的回复更好)我同意改变字典的值不应该涉及复制它,但这正是在这种情况下发生的情况,因为 Dictionary 和 Array 是如何实现的(字典的下标 getter 和 setter 都需要调用,并且数组无法知道对其底层引用的性质缓冲区,它只知道它正在被改变,而有两个东西查看它)以及编译器(尚未)将其识别为要优化的模式这一事实。
猜你喜欢
  • 1970-01-01
  • 2014-01-31
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2018-03-13
相关资源
最近更新 更多