6

I rewrite this code from php. And I find it difficult to make it work in swift.

var arrayOfData = [AnyObject]()

for index in 1...5 {
    var dict = [String: AnyObject]()
    dict["data"] = [1,2,3]
    dict["count"]  = 0

    arrayOfData.append(dict)
}

for d in arrayOfData {

    let data = d as AnyObject

    // I want to update the "count" value
    // data["count"] = 8
    print(data);
    break;
}
Ben
  • 1,906
  • 10
  • 31
  • 47

3 Answers3

6

Assuming your array has to be of form '[AnyObject]' then something like this:

var arrayOfData = [AnyObject]()

for index in 1...5 {
    var dict = [String: AnyObject]()
    dict["data"] = [1,2,3]
    dict["count"]  = 0

    arrayOfData.append(dict)
}

for d in arrayOfData {

    // check d is a dictionary, else continue to the next 
    guard let data = d as? [String: AnyObject] else { continue }

    data["count"] = 8
}

But preferably your array would be typed as an array of dictionaries:

var arrayOfData = [[String: AnyObject]]()

for index in 1...5 {
    var dict = [String: AnyObject]()
    dict["data"] = [1,2,3]
    dict["count"]  = 0

    arrayOfData.append(dict)
}

for d in arrayOfData {
    // swift knows that d is of type [String: AnyObject] already
    d["count"] = 8
}

EDIT:

So the issue is that when you modify in the loop, you're creating a new version of the dictionary from the array and need to transfer it back. Try using a map:

arrayOfData = arrayOfData.map{ originalDict in
    var newDict = originalDict
    newDict["count"] = 8
    return newDict
}
SeanCAtkinson
  • 753
  • 1
  • 4
  • 15
6

Presumably, you want to update the value inside of arrayOfData when you assign data["count"] = 8. If you switch to using NSMutableArray and NSMutableDictionary, then your code will work as you want. The reason this works is that these types are reference types (instead of value types like Swift arrays and dictionaries), so when you're working with them, you are referencing the values inside of them instead of making a copy.

var arrayOfData = NSMutableArray()

for index in 1...5 {
    var dict = NSMutableDictionary()
    dict["data"] = [1,2,3]
    dict["count"] = 0

    arrayOfData.addObject(dict)
}

for d in arrayOfData {
    let data = d as! NSMutableDictionary
    data["count"] = 8
    print(data)
    break
}
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • Awesome, Thank you! But compare to @SeanCAtkinson solution using map.Which one is better, performance speaking – Ben Jun 18 '16 at 21:33
  • `map` will recreate the `arrayOfData` which will be less efficient than this one since you're directly accessing the `arrayOfData` items and changing them. – vacawama Jun 18 '16 at 21:38
  • Yes, I see. And how to remove "let data..." and make "d" be with type NSMutableDictionary ? – Ben Jun 18 '16 at 21:42
  • I tried with "d: NSMutableDictionary in arrayOfData" – Ben Jun 18 '16 at 21:45
  • I don't think there is a way. `arrayOfData` is an `NSMutableArray` so the items inside are `AnyObject`. It is necessary to cast `d` to `NSMutableDictionary` which is what the `let data...` line does. This operation will be efficient, because `d` and `data` are referring to the same value in memory, but the compiler then knows the type of data that `data` references. – vacawama Jun 18 '16 at 21:48
  • You could do `(d as! NSMutableDictionary)["count"] = 8`, but I wouldn't. – vacawama Jun 18 '16 at 21:50
  • Thanks for the great explanation :) – Ben Jun 18 '16 at 21:55
  • The performance differences are barely worth mentioning and in fact are arguable as Swift is heavily optimised for value types. The main difference between the two approaches is that this is more 'traditional' iOS using reference types whereas mine takes a more swiftly approach using the value types in the standard library. Here is an article on where you can read more on the difference: https://developer.apple.com/swift/blog/?id=10 In reality though, the best solution in this case is to simply use whichever you understand the best. – SeanCAtkinson Jun 18 '16 at 22:55
  • What if you have a dictionary of structs? – Justin Meiners Aug 29 '22 at 23:16
0

The most efficient way would be to find the index of the relevant values entry, and then replace that entry. The index is essentially just a pointer into the hash table, so it's better than looking up by key twice:

To update all the entries, you can loop through the indices one at a time:

for i in dictionary.values.indices {
   dictionary.values[i].property = ...
}

To update a particular key, use:

let indexToUpdate = dictionary.values.index(forKey: "to_update") 
dictionary.values[i].property = ...
Justin Meiners
  • 10,754
  • 6
  • 50
  • 92