【问题标题】:swift: modifying arrays inside dictionariesswift:修改字典中的数组
【发布时间】:2014-08-23 10:16:16
【问题描述】:

如何轻松地将元素添加到字典内的数组中? 它总是抱怨could not find member 'append'could not find an overload for '+='

var dict = Dictionary<String, Array<Int>>()
dict["key"] = [1, 2, 3]

// all of these fail
dict["key"] += 4
dict["key"].append(4) // xcode suggests dict["key"].?.append(4) which also fails
dict["key"]!.append(4)
dict["key"]?.append(4)

// however, I can do this:
var arr = dict["key"]!
arr.append(4) // this alone doesn't affect dict because it's a value type (and was copied)
dict["key"] = arr

如果我只是将数组分配给一个 var,修改它,然后将它重新分配给 dict,我不会复制所有内容吗?这既不高效也不优雅。

【问题讨论】:

    标签: arrays dictionary syntax swift


    【解决方案1】:

    接受的答案绕过了以下更简单的可能性,这也适用于旧的 Swift 版本:

    var dict = Dictionary<String, Array<Int>>()
    dict["key"] = [1, 2, 3]
    
    print(dict)
    
    dict["key", default: [Int]()].append(4)
    
    print(dict)
    

    这将打印:

    ["key": [1, 2, 3]]
    ["key": [1, 2, 3, 4]]
    

    还有这个:

    var dict = Dictionary<String, Array<Int>>()
    dict["key", default: [Int]()].append(4)
    print(dict)
    

    将打印:

    ["key": [4]]
    

    【讨论】:

    • 很好的答案,可以用 dict["key" 进一步简化,默认值:[]].append(4)
    【解决方案2】:

    使用'for in',从字典的内部数组中获取值。这是一个可以帮助您的示例

    var a = ["x":["a","b","c"], "y":["d"]]
    
    for b in a {
        print(b)
    }
    

    输出:

    ("x", ["d"])
    ("y", ["a", "b", "c"])
    

    【讨论】:

      【解决方案3】:

      Swift beta 5 已添加此功能,并且您在几次尝试中就掌握了新方法。展开运算符!? 现在将值传递给运算符或方法调用。也就是说,您可以通过以下任何方式添加到该数组中:

      dict["key"]! += [4]
      dict["key"]!.append(4)
      dict["key"]?.append(4)
      

      与往常一样,请注意您使用的运算符 - 强制解包不在字典中的值会导致运行时错误:

      dict["no-key"]! += [5]        // CRASH!
      

      而使用可选链会默默地失败:

      dict["no-key"]?.append(5)     // Did it work? Swift won't tell you...
      

      理想情况下,您可以使用新的空合并运算符 ?? 来解决第二种情况,但现在这不起作用。


      Swift beta 5 之前的答案:

      这是 Swift 的一个怪癖,它不可能做你想做的事。问题是任何 Optional 变量的 value 实际上是一个常量——即使在强制展开时也是如此。如果我们只定义一个 Optional 数组,以下是我们能做和不能做的事情:

      var arr: Array<Int>? = [1, 2, 3]
      arr[0] = 5
      // doesn't work: you can't subscript an optional variable
      arr![0] = 5
      // doesn't work: constant arrays don't allow changing contents
      arr += 4
      // doesn't work: you can't append to an optional variable
      arr! += 4
      arr!.append(4)
      // these don't work: constant arrays can't have their length changed
      

      您在使用字典时遇到问题的原因是下标字典会返回一个可选值,因为无法保证字典将具有该键。因此,字典中的数组与上面的可选数组具有相同的行为:

      var dict = Dictionary<String, Array<Int>>()
      dict["key"] = [1, 2, 3]
      dict["key"][0] = 5         // doesn't work
      dict["key"]![0] = 5        // doesn't work
      dict["key"] += 4           // uh uh
      dict["key"]! += 4          // still no
      dict["key"]!.append(4)     // nope
      

      如果您需要更改字典中的数组中的某些内容,则需要获取数组的副本,对其进行更改并重新分配,如下所示:

      if var arr = dict["key"] {
          arr.append(4)
          dict["key"] = arr
      }
      

      ETA:相同的技术在 Swift beta 3 中有效,但常量数组不再允许更改内容。

      【讨论】:

      • 否 - 为字典下标会返回一个 Optional,因此就像在我的第一个示例中使用的可选数组一样。
      • 我不知道为什么Apple没有为数组定义+运算符。如果你自己做,你可以使用 dict["key"] = dict["key"]! + 4.
      • += 运算符已定义,但仅适用于可变数组。 dict["key"]! 是不可变的(它的长度不能改变)。当您使用dict["key"] = dict["key"]! + 4 时,您正在创建一个全新的数组并将其重新分配给dict["key"]——不同于.append(4)+= 4
      • 我没有说+=,我说的是+。显然,当您“添加”到不可变数组时,您将创建一个新数组(例如,您的 var arr = dict["key"]); Apple 应该处理 + 中的逻辑,然后将其复制到 +=。
      • 我要给你打个绿勾,我感到非常难过。真的吗,苹果?我希望如果他们不重新设计这部分语言,他们至少会特别针对这种情况制作一种新的语言结构。无论如何:我刚刚在操场上尝试了dict["key"] = dict["key"]!.append(4) 位,但我仍然收到could not find member 'append' 错误。什么给了?
      【解决方案4】:

      这是我在 cmets 中告诉 Nate Cook 的内容,以获得他的高质量回答。这就是我所认为的“轻松地将元素添加到字典中的数组”:

      dict["key"] = dict["key"]! + 4
      dict["key"] = dict["key"] ? dict["key"]! + 4 : [4]
      

      现在,我们需要自己定义 + 运算符。

      @infix func +<T>(array: T[], element: T) -> T[] {
          var copy = array
          copy += element
          return copy
      }
      

      我认为这个版本去除了太多的安全性;也许用复合运算符定义它?

      @infix func +<T>(array: T[]?, element: T) -> T[] {
          return array ? array! + element : [element]
      }
      
      dict["key"] = dict["key"] + 4
      

      最后,这是我能得到的最简洁的方法,但我对这个示例中数组值/引用的工作方式感到困惑。

      @assignment func +=<T>(inout array: T[]?, element: T) {
          array = array + element
      }
      
      dict["key"] += 5
      

      【讨论】:

      • 对于它的价值,这是一个了不起的解决方法。好吧,对于像我这样的人来说,至少还远远没有掌握 swift 的本质。我仍然有点担心它在后台复制东西而我忘记了它并在性能非常重要的紧密循环中使用它......
      【解决方案5】:

      作为一种简单的解决方法,您可以使用 NSMutableArray:

      import Foundation
      
      var dict = Dictionary<String, NSMutableArray>()
      dict["key"] = [1, 2, 3] as NSMutableArray
      dict["key"]!.addObject(4)
      

      我在我的项目中有效地使用了这种简单的解决方案:

      https://github.com/gui-dos/Guigna/blob/5c02f7e70c8ee3b2265f6916c6cbbe5cd3963fb5/Guigna-Swift/Guigna/GuignaAppDelegate.swift#L1150-L1157

      【讨论】:

      • 没错,因为NSMutableArray 是一个类,不像Swift 的原生数组,它被定义为结构。在这个实现中,dict["key"]! 仍然是不可变的,但这并不重要,因为您可以更改不可变类的底层属性。
      • 它确实有效,并且是一个非常简单和明智的解决方法。不过,我已经开始梦想 NS*-less 代码了 :(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-10
      • 2014-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多