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?

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


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.


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

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


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.


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


1

Beste Lösung für mich:

List temp = {1,2,3,4}
List platforms = json.decode(json.encode(parent.platforms));

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.


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


0

So kopieren Sie Map <String, List> gefiltert;

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

-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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.