Search code examples
iosswiftdictionarymultidimensional-arrayanyobject

Appending Multidimensional Dictionary


I have a multidimensional dictionary and I am trying to add data into it without deleting data, but overwrite if duplicate.

var items = [Int: AnyObject]()

var IdsAndDetails = [String:AnyObject]()
let index = 3 // static for test

...
for result in results {
     // result is String (result also indicates itemId)

     let details = self.IdsAndDetails[result]  
     // details is AnyObject like [String:String]

    if let itemDetails = details {        
         // Here I want to append data into 'items' variable

         // This doesn't work: (Error-1)
          self.items[index]![result] = itemDetails

    }

(Error-1):

Cannot assign to immutable expression to type AnyObject.


However, if I try like, it works but it's not the approach I want. It's re-creating the dictionary. Instead, I want to append the data.

      self.items = [
         index : [result : itemDetails]
      ]

The structure of dictionary I want to get in the end is:

items = [
    index : [
        "id1" : ["key": "value", "key": "value"],
        "id2" : ["key": "val", "key": "val"],
        ],
    index : [
        "id3" : ["key": "val", "key": "val"],
        "id4" : ["key": "val", "key": "val"],
        "id5" : ["key": "val", "key": "val"],
    ]
]

// index is Integer
// [Key:Value] is [String:String] - itemDetails equal to all `[key:value]`s
// 'id' is also String

Update: I also tried, but no luck

     let a = self.items[index]
     a![result]! = itemDetails as [String:String]

Update 2:

    let valueDict = (value as! NSDictionary) as Dictionary

    for (key, val) in valueDict {
        let keyString = key as! String
        let valString = val as! String

        self.items[index]![result]![keyString]! = valString
    }

But it's throwing error:

fatal error: unexpectedly found nil while unwrapping an Optional value

But Surprisingly debugging shows all values:

po index : 1
po itemId : "123123"
po keyString: "keyInString"
po valString: "valInString"

Update 3:

 for index in 1...5 {
   var results = [String]()

   // First I retrieve nearby users and assign it to key

   let itemsRef = Firebase(url: self.secret + "/items")
   eventsRef.queryOrderedByChild("user_id").queryEqualToValue(key).observeEventType(.ChildAdded, withBlock: { snapshot in
   // ^ above 'key' is the user_id retrieved before

   let itemDetails = snapshot.value // item details - [key:val, key:val]
   let itemId = snapshot.key        // item ids [id1,id2,id3]

   // I used 'KeyAndDetails' to store all values with ids 
   let IdsAndDetails = [itemId: itemDetails]

   self.itemIdsArray = []
   self.itemIdsArray.append(itemId)

   if index == 1 {
       // self.items = [
       //    index : [itemId : itemDetails]
       // ]
       // ^ This worked and gave me the structure
       // but I don't want to overwrite it, instead, I want to append
       // on the dictionary

       // This is where I am trying to append into `self.items`,
       // and throws error:
       self.items[index]?[result] = (eventDetails as! [String : String])
   }
  ...

Solution

  • It seems like you're trying to bypass Swift's type system instead of working with it. Instead of using AnyObject, you should be trying to use the exact type you want for the value of that dictionary. In this case it looks like you want something like [Int: [String: [String: String]]] (although, like @EricD said in the comments, you should probably be using a struct instead, if at all possible).

    Here's a quick (static) example similar to the code in your question:

    var items = [Int: [String: [String: String]]]()
    let idsAndDetails = ["id2": ["key3": "value3"]]
    
    let index = 3
    items[index] = ["id1": ["key1": "value1", "key2": "value2"]]
    
    let result = "id2"
    if let itemDetails = idsAndDetails[result] {
        items[index]?[result] = itemDetails
    }
    

    At the end of that, items will be:

    [3: ["id1": ["key1": "value1", "key2": "value2"], "id2": ["key3": "value3"]]]

    The ? in items[index]?[result] tells Swift to make sure items[index] is non-nil before attempting to execute the subscript method. That way, if you try to update an index that doesn't exist in items you don't cause a crash.