web-dev-qa-db-de.com

An Array in [String: Any] Wörterbuchstruktur anhängen

Beim Zusammenstellen einer Datennutzlast, die an GRMustache.Swift übergeben wird, um Schnurrbartvorlagen zu rendern, befinde ich mich in einem Szenario, in dem ich Daten an ein zuvor im Wörterbuch definiertes Array anhängen muss.

Meine Datenstruktur beginnt mit:

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

Das items-Schlüsselpaar ist eine Sammlung, die ich später in einer Schleife anfügen muss.

Um das data["items"]-Array hinzuzufügen, versuche ich Folgendes:

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

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

Dieser Fehler hat als Wert des Typs Any? kein Member append und der binäre Operator += kann nicht auf Operanden vom Typ Any? und [String : Any] angewendet werden.

Das macht Sinn, da ich den Wert anhängen muss; Ich kann das Array jedoch nicht mutieren.

Casting in Array, ob das Erzwingen des Downcasts den Fehler verursacht:

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

'Irgendein?' kann nicht in 'Array <_>' konvertiert werden; Wolltest du "als!" verwenden? niedergeschlagen zwingen

Mutationsmitglied kann nicht für unveränderliche Werte des Typs 'Array <_>' verwendet werden

Scheint, dass meine Besetzung falsch ist; oder, vielleicht gehe ich falsch vor.

Gibt es eine Empfehlung, wie Sie data["items"] im Laufe der Zeit iterativ füllen?

13
Jason Sturges

Der Typ von data[Items] ist nicht Array sondern tatsächlich Array<[String: Any]>.

Sie könnten dies wahrscheinlich in weniger Schritten zusammenpressen, aber ich bevorzuge die Klarheit mehrerer Schritte:

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

Wenn Sie lieber Kürze als Klarheit bevorzugen, können Sie diesen Vorgang in einer einzigen Zeile ausführen. Verwenden Sie dazu den nil-Koaleszenzoperator und den +-Operator für RangeReplaceableCollection (dem Array entspricht), wobei letzterer für den Schritt "Anhängen" verwendet wird (Erstellen einer neuen Sammlung, die die vorhandene ersetzt, wenn der Wert von data["items"] ersetzt wird).

// 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 mit Dictionary gibt immer eine optional(?)-Instanz zurück, da möglicherweise key nicht in Dictionary vorhanden ist. Jetzt haben Sie Ihr Wörterbuch als [String:Any] bezeichnet, wobei der Typ von keyString und valueAny ist.

Wenn Sie jetzt data["item"] schreiben, werden Sie Any? zurückgegeben, bei dem es sich nicht um Array handelt. Daher können Sie append nicht aufrufen. Es wird ein unveränderlicher Wert zurückgegeben, sodass Sie ihn nicht direkt mutieren können.

Sie müssen es also in Array of Dictionary umwandeln und in Instanz speichern und diese Instanz anfügen. Ersetzen Sie dann dieses Objekt in Ihrem Wörterbuch, indem Sie es neu zuweisen. 

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
}

Jetzt ist es viel einfacher, wenn Sie Dictionary wie [String: [[String:Any]]] für zB haben.

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

Ich bin mir nicht ganz sicher, ob dies für den Wörterbuchtyp [String: Any] funktioniert, empfehle jedoch dringend, eine Struktur zu erstellen, anstatt "Any" für Ihr Wörterbuch zu verwenden. Es hilft, die Dinge viel reibungsloser laufen zu lassen.

Andererseits wollte ich erwähnen, dass Sie etwas ausprobieren können wie:

yourDictionary["Key", default: []].append(item)

Dadurch wird ein Array für diesen "Schlüssel" initialisiert, der im Wörterbuch verwendet wird, wenn noch kein Array initialisiert wurde. Ohne dies müssten Sie das Array selbst überprüfen und initialisieren, was letztendlich zu einem sich wiederholenden Code führt.

Hoffe das hilft.

0
C0D3

Gib dir eine Array von items:[String]

Er kann dies auch dem Json hinzufügen

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

data["items"] = items
0
muescha