Добавить к массиву в структуре словаря [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 < _ > '; вы хотели использовать "как!" заставить downcast?

Нельзя использовать мутирующий элемент в неизменяемом значении типа 'Array < _ > '

Похоже, что мое приведение неверно; или, возможно, я собираюсь сделать это не так.

Любая рекомендация о том, как заполнить data["items"] итеративно с течением времени?

Ответ 1

Тип 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
}

Ответ 2

subscript с Dictionary всегда возвращает экземпляр optional(?), потому что возможно, что key не существует в Dictionary. Теперь вы объявляете свой словарь как [String:Any] означает, что тип key is String и value is Any.

Теперь, когда вы пишете data["item"], он вернет вам Any?, который не является массивом, поэтому вы не можете вызвать append, и он вернет неизменяемое значение, чтобы вы не могли напрямую его мутировать.

Итак, вам нужно набрать текст в Array of Dictionary и сохранить его в экземпляре и добавить этот экземпляр после этого, заменив этот объект в словаре, используя его повторное назначение.

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) 
}

Ответ 3

Если вы предпочитаете краткость по ясности, вы можете выполнить эту операцию в одной строке, используя оператор коалесцирования nil и + оператор для RangeReplaceableCollection (к которому соответствует 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"]       */

Ответ 4

Дайте вам Array items:[String]

Он также может добавить это в json

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

data["items"] = items

Ответ 5

Я не совсем уверен, работает ли это в словаре типа [String: Any], но я также настоятельно рекомендую вам создать структуру вместо использования "Any" для вашего словаря. Это поможет сделать вещи намного более гладкими.

С другой стороны, я хотел бы упомянуть, вы можете попробовать что-то вроде:

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

Это инициализирует массив для этого "Ключа", который будет использоваться в словаре, если еще не инициализирован массив. Без этого вам придется самостоятельно проверять и инициализировать массив, который в конечном итоге станет повторяющимся кодом.

Надеюсь это поможет.