2017-01-07 28 views
9

Składanie ładunku danych przekazywanego do GRMustache.swift w celu renderowania szablonów wąsów, znajduję się w scenariuszu, w którym muszę dołączyć dane do tablicy zdefiniowanej wcześniej w słowniku.Dołącz do tablicy w [Ciąg: Dowolny] struktura słownika

Moja struktura danych zaczyna się jako:

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

items para kluczy jest zbiorem muszę dołączyć później w pętli.

Aby dodać do tablicy data["items"], próbuję coś takiego:

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

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

tej błędów, jako wartość typu Any? ma człon append i operator binarny += nie mogą być stosowane do argumentów typu Any? i [String : Any].

Ma to sens, ponieważ potrzebuję rzucić wartość, aby dołączyć; jednak nie mogę zmutować tablicy.

Casting do tablicy, czy zmuszanie spuszczonymi daje błąd:

(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<_>'

Wygląda jak moja obsada jest źle; lub, być może, podchodzę do tego w niewłaściwy sposób.

Czy istnieje jakieś zalecenie dotyczące wypełniania w miarę upływu czasu data["items"]?

Odpowiedz

6

Typ data[Items] nie jest Array, ale faktycznie Array<[String: Any]>.

Można prawdopodobnie zmieścić to w mniejszej liczbie etapów, ale wolę klarowność wielu etapach:

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

subscript z Dictionary zawsze powrócić optional(?) instancji, ponieważ może się zdarzyć, że nie istnieje key w Dictionary. Teraz zadeklarowałeś swój słownik jako [String:Any] oznacza typ key jest String i value jest Any.

Teraz kiedy piszesz data["item"] zwróci Ci Any? że nie jest Array, więc nie można o nazwie append i zwróci wartość niezmienna, więc nie można go bezpośrednio mutować.

Musisz więc wpisać go do Array of Dictionary i zapisać go w instancji, a następnie dodać tę instancję, aby zastąpić ten obiekt w słowniku przy użyciu ponownego przypisywania.

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 
} 

Teraz sprawa mam dużo łatwiejsze, jeśli masz Dictionary jak [String: [[String:Any]]] dla np.

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

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

@JasonSturges wiem, mam tylko pokazać, co było problemem i gdzie można bezpośrednio dołącz tablicę, która była w słowniku. –

+1

Naprawdę doceniam klarowność i elegancję napisu "[String: [[String: Any]]]. –

+0

Zwróć uwagę, że możesz użyć 'data [" items "]? Append (item)' zamiast 'data [" items "]!. Append (item)' above; ten drugi spowoduje awarię środowiska wykonawczego, jeśli nie będzie żadnej wartości dla '' items "' klucza (nawet jeśli wiemy, że jest w tym przykładzie), podczas gdy ten pierwszy po prostu zwróci niewykorzystany 'nil'. Nawet jeśli wiemy, że klucz do "elementów" istnieje, uważam, że powinniśmy preferować bezpieczne podejście, zwłaszcza gdy nie wiąże się to z dodatkowymi kosztami. Zawsze ryzyko wzmocnienia złego '' 'praktyki dla początkujących czytelników SO, którzy nie zdają sobie sprawy, że w tym konkretnym przypadku/przykładu,'! 'Jest bezpieczne, ale poza tym, na ogół nie jest. – dfri

3

Jeśli wolisz zwięzłość nad jasności, można wykonać tę operację w jednej linii, dzięki czemu korzystanie z nil zlewających operatora i the + operator for RangeReplaceableCollection (do którego Array zgodny), drugi służy do „Dołącz” Krok (w rzeczywistości budowanie nowej kolekcji, która zastąpi istniejącą, zastępując wartość 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"]  */ 
0

daje mieć Array z items:[String]

Może też dodać to do json

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

data["items"] = items