0

I have a nested dictionary in which a deep node is an array. When I attempt to append an element to the array element of the dictionary I get a compile error. What I am trying is to replace the

["000" : "OK"]

if the key is the same "000" or append to the existing elements if the key is different such as in

["001" : "Good"]

. Appreciate some guidance or alternate method to update. The error I get is:

Cannot use mutating member on immutable value of type '[[String : String]]'

B = [ "EA" : [ "status": [["000": "OK"]]]]
B["EA"]?["status"] = [["000": "NOT OK"]]
print(B)

(B["EA"]?["status"])?.append(["001":"Good"])
Hamish
  • 78,605
  • 19
  • 187
  • 280
Syed Tariq
  • 2,878
  • 3
  • 27
  • 37
  • 1
    Possible duplicate of [How to append to an array that is a value in a Swift dictionary](http://stackoverflow.com/questions/28376067/how-to-append-to-an-array-that-is-a-value-in-a-swift-dictionary) – matt Mar 07 '17 at 02:47
  • Just remove the parenthesis – `b["EA"]?["status"]?.append(["001":"Good"])`. Although note that this isn't particularly efficient as I believe both the array and inner dictionary will be copied. See http://stackoverflow.com/q/41079687/2976878 for a way to avoid this. – Hamish Mar 07 '17 at 02:49
  • But really, using a dictionary of dictionaries with array values of dictionaries is almost certainly an indication that you should be using some other data structure. If your dictionaries have static keys, they should be structs. – Hamish Mar 07 '17 at 03:02
  • Very valid point and one that I am struggling with. I have a form that maps into the dictionary. There are a lot of elements in the form but not all are filled up. I need to log which are filled up so I am saving only the elements that were entered or changed. To complicate the problem, the user may want to hang on to previous entries of the same field. My data record looks something like this: [ module: [field: [ [version:value] ]]]. I am contemplating breaking up the array. – Syed Tariq Mar 07 '17 at 03:50

2 Answers2

1

You do it the same way Superman gets into his pants — one leg at a time. Pull out the array, append to it, put it back again:

var B = [ "EA" : [ "status": [["000": "OK"]]]]
B["EA"]?["status"] = [["000": "NOT OK"]]

print(B) // ["EA": ["status": [["000": "NOT OK"]]]]

if var arr = B["EA"]?["status"] {
    arr.append(["001":"Good"])
    B["EA"]?["status"] = arr
}

print(B) // ["EA": ["status": [["000": "NOT OK"], ["001": "Good"]]]]
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Matt - Thank you for the clear example and for your books on IOS 10 which I try always to use as the first step in my quest for answers. I guess I should have read your books more carefully but there is sooooo much stuff in them, it is tough for me to keep up. – Syed Tariq Mar 07 '17 at 03:20
  • Unfortunately my "Superman's pants" joke is also in the book somewhere! I probably need better jokes. – matt Mar 07 '17 at 03:26
1

Because both dictionary and array in Swift is struct type.
You can make B 's type explicit.Like:

var B:[String:[String:NSMutableArray]] = [ "EA" : [ "status": [["000": "OK"]]]]
B["EA"]?["status"] = [["000": "NOT OK"]]
print(B)
//["EA": ["status":{
//    000 = "NOT OK";
//    }
//    ]]

Then you can use the NSMutableArray method add()

(B["EA"]?["status"])?.add(["001":"Good"])
print(B)
//["EA": ["status":{
//    000 = "NOT OK";
//    },
//    {
//    001 = Good;
//    }
//    ]]
TanJunHao
  • 216
  • 2
  • 2