Klonen Sie eine Liste, eine Karte oder ein Set in Dart

74

Aus einem Java-Hintergrund kommend: Was ist die empfohlene Methode, um einen Dart zu "klonen" List, Mapund Set?

Patrice Chalin
quelle

Antworten:

88

Die Verwendung clone()in Java ist schwierig und fragwürdig 1,2 . Effektiv clone()ist ein Kopierkonstruktor und dafür die Dart List, Mapund SetArten haben jeweils einen Namen Konstruktor genannt , .from()die eine ausführen flache Kopie ; zB angesichts dieser Erklärungen

  Map<String, int> numMoons, moreMoons;
  numMoons = const <String,int>{ 'Mars' : 2, 'Jupiter' : 27 };
  List<String> planets, morePlanets;

Sie können .from()wie folgt verwenden:

  moreMoons = new Map<String,int>.from(numMoons)
    ..addAll({'Saturn' : 53 });
  planets = new List<String>.from(numMoons.keys);
  morePlanets = new List<String>.from(planets)
    ..add('Pluto');

Beachten Sie, dass List.from()im Allgemeinen ein Iterator akzeptiert wird und nicht nur ein List.

Der Vollständigkeit halber sollte ich erwähnen, dass die dart:html NodeKlasse eine clone () -Methode definiert.


1 J. Bloch, " Effective Java ", 2. Aufl., Punkt 11.
2 B. Venners, " Josh Bloch über Design: Kopierkonstruktor versus Klonen ", 2002 . Von hier aus referenziert 3 . Zitat aus dem Artikel:

Wenn Sie den Artikel über das Klonen in meinem Buch gelesen haben, insbesondere wenn Sie zwischen den Zeilen lesen, werden Sie wissen, dass ich denke, dass der Klon tief gebrochen ist. --- J.Bloch

3 Dart Issue # 6459, Kloninstanz (Objekt) .

Patrice Chalin
quelle
8
Josh Bloch war tatsächlich an einigen frühen Entwürfen der Dart-Sammlungs-API beteiligt. Altes Interview .
Greg Lowe
3
Die Dateien .from () und .addAll () machen keinen Klon. Sie fügen eine Referenz in die neue Karte / Liste / Menge ein. Zum Beispiel: Map map1 = {'eins': {'Name': 1}, 'zwei': {'Name': 2}, 'drei': [{'a': {'A': 1, 'B. ': 2},' b ': {' A ': 3,' B ': 4}}]}; Map map2 = new Map.from (map1); map2 ['two'] ['name'] = 4; Nach dem Ändern von map2 ['two'] ['name'] änderte sich auch
map1
1
Richtig. .from()ist ein flacher Kopierkonstruktor. Um ganz klar zu sein, ich habe nie gesagt, dass .from()eine Klonoperation durchgeführt wurde. Was ich schrieb, war clone()eine Art Kopierkonstruktor.
Patrice Chalin
1
Denken Sie daran List, List<E>.of()dass es besser sein könnte , wenn Sie den Typ des Originals kennen .
Michael Pfaff
26

Für Listen und Sets verwende ich normalerweise

List<String> clone = []..addAll(originalList);

Die Einschränkung, wie @kzhdev erwähnt, ist das addAll()undfrom()

Machen Sie keinen Klon. Sie fügen eine Referenz in die neue Karte / Liste / Menge ein.

Das ist normalerweise in Ordnung für mich, aber ich würde es mir merken.

Stevenspiel
quelle
20

Wenn Sie dart> 2.3.0 verwenden, können Sie den Spread-Operator wie folgt verwenden:

List<int> a = [1,2,3];
List<int> b = [...a]; // copy of a
Abhishek Kanojia
quelle
2
Beachten Sie, dass dadurch keine Liste von Objekten geklont wird. Die Liste enthält Referenzen.
ZeroNine
6

Diese Lösung sollte funktionieren:

  List list1 = [1,2,3,4]; 

  List list2 = list1.map((element)=>element).toList();

Es ist für eine Liste, sollte aber für eine Karte usw. genauso funktionieren. Denken Sie daran, es zur Liste hinzuzufügen, wenn es am Ende eine Liste ist

CodeMemory
quelle
5

Für Deep Copy (Klon) können Sie Folgendes verwenden:

Map<String, dynamic> src = {'a': 123, 'b': 456};
Map<String, dynamic> copy = json.decode(json.encode(src));

Es kann jedoch Bedenken hinsichtlich der Leistung geben.

Karpour
quelle
1
Ich verstehe nicht ganz, warum diese Antwort abgelehnt wurde, da sie wirklich einen Vorteil hat. Ja, es wird einige Leistungsprobleme geben, aber es werden wirklich KOPIEN von Listen erstellt, nicht nur ein Link zu ihnen kopiert. Also werde ich dir eine Gegenstimme geben
Konstantin
Ihre Antwort funktioniert nur, wenn nur primitive Attribute vorhanden sind. Stellen Sie sich vor, Sie haben Getter / Setter / Funktionen. json.decode-> encode wird das alles
kaputt machen
@qiAlex das ist offensichtlich, aber es ist ein Weg, den jemand wählen kann, Alter. Wenn Sie häufig klonen und Objekte erstellen möchten, enthält dies häufig Grundelemente. Was bedeutet, eine Funktion zu klonen!
Karpour
3

Map.from () funktioniert nur für 1D-Karten.

Verwenden Sie die folgende Methode, um eine mehrdimensionale Karte ohne Referenz in Dart zu kopieren


    Map<keyType, valueType> copyDeepMap( Map<keyType, valueType> map )
    {
        Map<keyType, valueType> newMap = {};

        map.forEach
        (
            (key, value)
            {
                newMap[key] =( value is Map ) ? copyDeepMap(value) : value ;
            }
        );

        return newMap;
    }

Manish Dhruw
quelle
1

Beste Lösung für mich:

List temp = {1,2,3,4}
List platforms = json.decode(json.encode(parent.platforms));
Serg
quelle
Dies funktioniert nicht, wenn Sie DateTime in der Liste / Karte / Gruppe verwenden, die Sie kopieren.
Swift
1

Mit der neuen Version des Dart-Klonens einer Karte oder Liste wird das ganz einfach. Sie können diese Methode ausprobieren, um einen tiefen Klon von Liste und Karte zu erstellen.

Für Liste

List a = ['x','y', 'z'];
List b = [...a];

Für Karten

Map mapA = {"a":"b"};
Map mapB = {...mapA};

Ich hoffe jemand findet das hilfreich.

Shubham Kumar
quelle
0

Das war meine Lösung. Ich hoffe es kann jemandem helfen.

  factory Product.deepCopy(Product productToCopy) => new Product(
    productToCopy.id,
    productToCopy.title,
    productToCopy.description,
    productToCopy.price,
    productToCopy.imageUrl,
    productToCopy.isFavorite,
  );}

PaulDev
quelle
0

So kopieren Sie Map <String, List> gefiltert;

 var filteredNewCopy = filtered.map((key, value) => MapEntry(key, [...value]));
sonOfWidgets
quelle
-1

Die gegebene Antwort ist gut, aber beachten Sie den generateKonstruktor, der hilfreich ist, wenn Sie eine Liste mit fester Länge "vergrößern" möchten, z.

List<String> list = new List<String>(5);
int depth = 0; // a variable to track what index we're using

...
depth++;
if (list.length <= depth) {
  list = new List<String>.generate(depth * 2,
      (int index) => index < depth ? list[index] : null,
      growable: false);
}
Dan Field
quelle