web-dev-qa-db-fra.com

Ajouter au tableau dans la structure du dictionnaire [String: Any]

Assemblage d'une charge de données transmise à GRMustache.Swift pour le rendu des modèles de moustache, je suis dans un scénario où je dois ajouter des données à un tableau précédemment défini dans le dictionnaire.

Ma structure de données commence par:

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

La paire de clés items est une collection que je dois ajouter plus tard dans une boucle.

Pour ajouter au tableau data["items"], j'essaie quelque chose comme:

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

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

Cette erreur se produit car la valeur de type Any? n'a pas de membre append et que l'opérateur binaire += ne peut pas être appliqué aux opérandes de type Any? et [String : Any].

Cela a du sens, car je dois convertir la valeur à ajouter; Cependant, je ne peux pas muter le tableau.

Lors de la conversion dans un tableau, si forcer le downcast donne l'erreur:

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

'Tout?' n'est pas convertible en 'Array <_>'; vouliez-vous utiliser 'comme!' forcer baissé?

Impossible d'utiliser un membre en mutation sur une valeur immuable de type 'Array <_>'

On dirait que mon casting est faux; ou peut-être que je m'y prends mal.

Une recommandation sur la façon de remplir data["items"] de manière itérative au fil du temps?

13
Jason Sturges

Le type de data[Items] n'est pas Array mais en réalité Array<[String: Any]>.

Vous pourriez probablement réduire cela en moins d'étapes, mais je préfère la clarté de plusieurs étapes:

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
}
12
MathewS

Si vous préférez la brièveté à la clarté, vous pouvez effectuer cette opération sur une seule ligne, en utilisant l'opérateur nil de coalescing et l'opérateur + pour RangeReplaceableCollection (auquel Array est conforme), ce dernier étant utilisé pour l'étape "ajouter" (En fait, construire une nouvelle collection qui remplacera celle existante en remplaçant la valeur de 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"]       */
4
dfri

subscript avec Dictionary retournera toujours l'instance optional(?) car il est possible que key n'existe pas dans Dictionary. Maintenant que vous avez déclaré votre dictionnaire comme suit: [String:Any] signifie que le type de key est String et value est Any.

Maintenant, lorsque vous écrivez data["item"], il retournera votre Any? qui n'est pas un tableau, vous ne pouvez donc pas appeler append et il retournera une valeur immuable afin que vous ne puissiez pas le muter directement.

Vous devez donc le transtyper dans Array of Dictionary et le stocker dans une instance, puis ajouter cette instance après avoir remplacé cet objet dans votre dictionnaire en le réaffectant. 

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

    var array = data["items"] as? [[String:Any]] ?? [[String:Any]]()
    array.append(item)
    data["items"] = array
}

Maintenant, la chose est beaucoup plus facile si vous avez Dictionary comme [String: [[String:Any]]] pour par exemple.

var data: [String: [[String:Any]]] = [
    "items": []
]

for index in 1...3 {
    let item: [String: Any] = [
        "key": "new value"
    ]
    data["items"]?.append(item) 
}
4
Nirav D

Vous donner une Array de items:[String]

Il peut aussi ajouter ceci au json

var items = ["string1", "Info 2","Text 4"]

data["items"] = items
0
muescha