2014-07-02 17 views
24

Wie kann ich einfach Elemente zu einem Array in einem Wörterbuch hinzufügen? Es beschwert sich immer mit could not find member 'append' oder could not find an overload for '+='swift: Ändern von Arrays in Wörterbüchern

var dict = Dictionary<String, Array<Int>>() 
dict["key"] = [1, 2, 3] 

// all of these fail 
dict["key"] += 4 
dict["key"].append(4) // xcode suggests dict["key"].?.append(4) which also fails 
dict["key"]!.append(4) 
dict["key"]?.append(4) 

// however, I can do this: 
var arr = dict["key"]! 
arr.append(4) // this alone doesn't affect dict because it's a value type (and was copied) 
dict["key"] = arr 

wenn ich das Array zu einem var nur zuweisen, es ändern und sie dann an die dict neu zuzuweisen, werde ich alles sein Kopieren nicht? das wäre weder effizient noch elegant.

Antwort

29

Swift Beta 5 hat diese Funktionalität hinzugefügt, und Sie haben die neue Methode in ein paar Ihrer Versuche genagelt. Die Unwrapping-Operatoren ! und ? übergeben den Wert nun an Operatoren oder Methodenaufrufe. Das heißt, Sie zu diesem Array in eine der folgenden Arten hinzufügen:

dict["key"]! += [4] 
dict["key"]!.append(4) 
dict["key"]?.append(4) 

Wie immer vorsichtig sein, welchen Operator Sie verwenden - force Wert auspackt, die nicht in Ihrem Wörterbuch ist wird Ihnen ein Laufzeitfehler:

dict["no-key"]! += [5]  // CRASH! 

Während optional Verkettung mit lautlos fehl:

dict["no-key"]?.append(5)  // Did it work? Swift won't tell you... 

Im Idealfall würde Sie in der Lage sein, den neuen Null Koaleszierstruktur Operator verwendet ?? diese zweite Adresse Fall, aber im Moment funktioniert das nicht.


Antwort von Pre-Swift Beta 5:

Es ist eine Marotte von Swift, dass es nicht möglich ist, zu tun, was Sie zu tun versuchen. Das Problem ist, dass der Wert einer optionalen Variable in der Tat eine Konstante ist - auch wenn er zwangsweise auspacken. Wenn wir nur ein optionales Array definieren, hier ist das, was wir können und nicht tun können:

var arr: Array<Int>? = [1, 2, 3] 
arr[0] = 5 
// doesn't work: you can't subscript an optional variable 
arr![0] = 5 
// doesn't work: constant arrays don't allow changing contents 
arr += 4 
// doesn't work: you can't append to an optional variable 
arr! += 4 
arr!.append(4) 
// these don't work: constant arrays can't have their length changed 

Der Grund sind Probleme mit dem Wörterbuch ist, dass ein Wörterbuch Indizierung eines optionalen Wert zurückgibt, da es keine Garantie gibt, dass Das Wörterbuch wird diesen Schlüssel haben. Daher hat ein Array in einem Wörterbuch das gleiche Verhalten wie das Fakultativ Array vor:

var dict = Dictionary<String, Array<Int>>() 
dict["key"] = [1, 2, 3] 
dict["key"][0] = 5   // doesn't work 
dict["key"]![0] = 5  // doesn't work 
dict["key"] += 4   // uh uh 
dict["key"]! += 4   // still no 
dict["key"]!.append(4)  // nope 

Wenn Sie etwas in einem Array im Wörterbuch ändern benötigen Sie eine Kopie des Arrays, ändern erhalten müssen es und neu zuzuweisen, wie folgt aus:

if var arr = dict["key"] { 
    arr.append(4) 
    dict["key"] = arr 
} 

ETA: Der gleiche Technik funktioniert in Swift beta 3, obwohl konstante Arrays nicht mehr Änderungen an Inhalten ermöglichen.

+0

Sollte nicht 'dict [ "key"] !. anhängen (4)' Arbeit dann? –

+1

Nein - Subskribierung eines Wörterbuchs gibt Ihnen ein Optional zurück, so dass Sie mit dem optionalen Array in meinem ersten Beispiel arbeiten. –

+0

Ich weiß nicht, warum Apple den Operator + für Arrays nicht definiert hat. Wenn Sie es selbst tun, können Sie dict ["key"] = dict ["key"] verwenden! + 4. – Jessy

6

Als einfache Abhilfe Sie eine NSMutableArray verwenden können:

import Foundation 

var dict = Dictionary<String, NSMutableArray>() 
dict["key"] = [1, 2, 3] as NSMutableArray 
dict["key"]!.addObject(4) 

Ich verwende effektiv solche einfache Lösung in meinem Projekt:

https://github.com/gui-dos/Guigna/blob/5c02f7e70c8ee3b2265f6916c6cbbe5cd3963fb5/Guigna-Swift/Guigna/GuignaAppDelegate.swift#L1150-L1157

+3

Das stimmt, denn 'NSMutableArray' ist eine Klasse, anders als die nativen Swift-Arrays, die als Strukturen definiert sind. In dieser Implementierung ist 'dict [" key "]!' Immer noch unveränderbar, aber das macht nichts, da Sie die zugrunde liegenden Eigenschaften einer unveränderlichen Klasse ändern können. –

+3

Es funktioniert und ist eine sehr einfache und sinnvolle Problemumgehung. Ich hatte bereits damit begonnen, von NS * -losem Code zu träumen, aber :( – figha

1

Hier ist, was ich zu sagen Nate Koch, in den Kommentaren für seine Qualitätsantwort.Dies ist, was ich „leicht [Hinzufügen] Elemente zu einem Array in einem Wörterbuch“ betrachten:

dict["key"] = dict["key"]! + 4 
dict["key"] = dict["key"] ? dict["key"]! + 4 : [4] 

Vorerst müssen wir den Operator + selbst definieren.

@infix func +<T>(array: T[], element: T) -> T[] { 
    var copy = array 
    copy += element 
    return copy 
} 

Ich denke, diese Version entfernt zu viel Sicherheit; vielleicht mit einem zusammengesetzten Operator definieren?

@infix func +<T>(array: T[]?, element: T) -> T[] { 
    return array ? array! + element : [element] 
} 

dict["key"] = dict["key"] + 4 

Schließlich ist dies die sauberste, das ich es bekommen kann, aber ich bin verwirrt darüber, wie Array-Werte/Referenzen in diesem Beispiel arbeiten.

@assignment func +=<T>(inout array: T[]?, element: T) { 
    array = array + element 
} 

dict["key"] += 5 
+1

Für was es wert ist, es ist eine erstaunliche Abhilfe. Nun, für jemanden wie mich, der immer noch weit davon entfernt ist, die Kleinigkeiten von swift zu bekommen, zumindest. Ich bin immer noch ein bisschen besorgt darüber, dass es Sachen im Hintergrund kopiert und ich es vergesse und es in einer engen Schleife benutze, wo Leistung sehr wichtig ist ... – figha

0

Verwenden Sie 'for in', um Werte aus dem internen Array des Wörterbuchs zu erhalten. Hier ist ein Beispiel, um Ihnen

var a = ["x":["a","b","c"], "y":["d"]] 

for b in a { 
    print(b) 
} 

Ausgang:

("x", ["d"]) 
("y", ["a", "b", "c"]) 
Verwandte Themen