web-dev-qa-db-ja.com

[String:Any]辞書構造の配列に追加

GRMustache.Swift に渡されるデータペイロードをアセンブルして、口ひげテンプレートをレンダリングするために、以前に辞書で定義された配列にデータを追加する必要があるシナリオにいます。

私のデータ構造は次のように始まります:

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

itemsキーペアは、後でループ内に追加する必要があるコレクションです。

data["items"]配列に追加するには、次のようなものを試しています:

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

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

タイプAny?の値にはメンバーappendがなく、バイナリ演算子+=をタイプAny?および[String : Any]のオペランドに適用できないため、このエラーが発生します。

追加する値をキャストする必要があるため、これは理にかなっています。ただし、配列を変更することはできません。

ダウンキャストを強制するとエラーが発生するかどうかにかかわらず、配列にキャストします。

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

'どれか?' 'Array <_>'に変換できません; 「as!」を使用するつもりでしたかダウンキャストを強制するには?

タイプ 'Array <_>'の不変の値では変更メンバーを使用できません

私のキャストが間違っているようです。または、おそらく私はこれについて間違った方法で行っています。

data["items"]を時間をかけて繰り返し入力する方法に関する推奨事項はありますか?

13
Jason Sturges

data[Items]のタイプはArrayではなく、実際にはArray<[String: Any]>です。

おそらくこれをより少ないステップに絞ることができますが、複数のステップを明確にすることを好みます。

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

明快さよりも簡潔さを好む場合は、nil合体演算子と RangeReplaceableCollection の_+_演算子を使用して、この操作を1行で実行できます。 Arrayが準拠する)、後者は「追加」ステップに使用されます(実際、_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"]       */
_
5
dfri

subscriptDictionaryに存在しない可能性があるため、keyDictionaryとともに常にoptional(?)インスタンスを返します。これで、[String:Any]keyのタイプがStringであり、valueAnyであると辞書を宣言しました。

data["item"]を記述すると、配列ではないAny?が返されるため、appendを呼び出せず、不変の値を返すため、直接変更することはできません。

したがって、辞書の配列にキャストして入力し、インスタンスに保存し、再割り当てを使用して辞書内のオブジェクトを置き換えた後にそのインスタンスを追加する必要があります。

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
}

Dictionaryのような[String: [[String:Any]]]があれば、これは非常に簡単になります。

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

これが[String:Any]タイプの辞書で機能するかどうかはわかりませんが、辞書に「Any」を使用する代わりに構造体を作成することを強くお勧めします。物事をよりスムーズに実行するのに役立ちます。

一方、言及したかったのは、次のようなものを試すことができるということです。

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

これにより、初期化された配列がまだない場合に辞書で使用される「キー」の配列が初期化されます。これがないと、配列を自分でチェックして初期化する必要があり、結果として反復コードになります。

お役に立てれば。

0
C0D3

Arrayitems:[String]

彼はこれをjsonに追加することもできます

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

data["items"] = items
0
muescha