Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append to array in [String: Any] dictionary structure

Assembling a data payload passed to GRMustache.swift for rendering mustache templates, I'm in a scenario where I need to append data to an array previously defined in the dictionary.

My data structure starts off as:

var data: [String: Any] = [
    "key1": "example value 1",
    "key2": "example value 2",
    "items": [
        // I need to append here later
    ]
]

The items key pair is a collection I need to append later within a loop.

To add to the data["items"] array, I'm trying something like:

for index in 1...3 {
    let item: [String: Any] = [
        "key": "new value"
    ]

    data["items"].append(item)
}

This errors, as value of type Any? has no member append, and binary operator += cannot be applied to operands of type Any? and [String : Any].

This makes sense, as I need to cast the value to append; however, I can't mutate the array.

Casting to array, whether forcing downcast gives the error:

(data["items"] as! Array).append(item)

'Any?' is not convertible to 'Array<_>'; did you mean to use 'as!' to force downcast?

Cannot use mutating member on immutable value of type 'Array<_>'

Seems like my cast is wrong; or, perhaps I'm going about this in the wrong way.

Any recommendation on how to fill data["items"] iteratively over time?

like image 514
Jason Sturges Avatar asked Jan 07 '17 06:01

Jason Sturges


People also ask

Can an array be a dictionary key?

A Dictionary object contains a set of key-item pairs. A dictionary's item is a value that is unambiguously associated with a unique key and the key is used to retrieve the item. The key can be of any type except a variant or an array (but generally it is a string or still an integer).

What is string any?

Now you have declare your dictionary as [String:Any] means type of key is String and value is Any . Now when you write data["item"] it will return you Any? that is not Array so you can not called append and it will return immutable value so you can't directly mutate it.

How is a dictionary different from an array?

Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations. Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store.


2 Answers

The type of data[Items] isn't Array but actually Array<[String: Any]>.

You could probably squeeze this into fewer steps, but I prefer the clarity of multiple steps:

var data: [String: Any] = [
    "key1": "example value 1",
    "key2": "example value 2",
    "items": []
]

for index in 1...3 {

    let item: [String: Any] = [
        "key": "new value"
    ]

    // get existing items, or create new array if doesn't exist
    var existingItems = data["items"] as? [[String: Any]] ?? [[String: Any]]()

    // append the item
    existingItems.append(item)

    // replace back into `data`
    data["items"] = existingItems
}
like image 112
MathewS Avatar answered Nov 04 '22 05:11

MathewS


If you prefer brevity over clarity, you can perform this operation in a single line, making use of the nil coalescing operator and the + operator for RangeReplaceableCollection (to which Array conforms), the latter used for the "append" step (in fact constructing a new collection which will the replace the existing one when replacing the value of data["items"]).

// example setup
var data: [String: Any] = [
    "key1": "example value 1",
    "key2": "example value 2",
    "items": []
]

// copy-mutate-replace the "items" array inline, adding a new dictionary
data["items"] = (data["items"] as? [[String: Any]] ?? []) + [["key": "new value"]]

print(data)
/* ["key2": "example value 2", 
    "items": [["key": "new value"]], 
    "key1": "example value 1"]       */

// add another dictionary to the "items" array
data["items"] = (data["items"] as? [[String: Any]] ?? []) + [["key": "new value"]]

print(data)
/* ["key2": "example value 2",
 "items": [["key": "new value"], ["key": "new value"]],
 "key1": "example value 1"]       */
like image 23
dfrib Avatar answered Nov 04 '22 06:11

dfrib