Clone a List, Map or Set in Dart

CollectionsDartClone

Collections Problem Overview


Coming from a Java background: what is the recommended way to "clone" a Dart List, Map and Set?

Collections Solutions


Solution 1 - Collections

Use of clone() in Java is tricky and questionable1,2. Effectively, clone() is a copy constructor and for that, the Dart List, Map and Set types each have a named constructor named .from() that perform a shallow copy; e.g. given these declarations

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

you can use .from() like this:

  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');

Note that List.from() more generally accepts an iterator rather than just a List.

For sake of completeness, I should mention that the dart:html Node class defines a clone() method.


1 J. Bloch, "Effective Java" 2nd Ed., Item 11.
2 B. Venners, "Josh Bloch on Design: Copy Constructor versus Cloning", 2002. Referenced from here3. Quote from the article: >> If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. ---J.Bloch

3 Dart Issue #6459, clone instance(object).

Solution 2 - Collections

With the new version of dart cloning of a Map or List become quite easy. You can try this method for making a deep clone of List and Map.

For List

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

For Maps

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

For Sets

Set setA = {1,2,3,};
Set setB = {...setA};

I hope someone find this helpful.

Solution 3 - Collections

If you are using dart > 2.3.0, You can use spread operator something like:

List<int> a = [1,2,3];
List<int> b = [...a]; // copy of a

Solution 4 - Collections

For lists and sets, I typically use

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

The caveat, as @kzhdev mentions, is that addAll() and from()

> [Do] not really make a clone. They add a reference in the new Map/List/Set.

That's usually ok with me, but I would keep it in mind.

Solution 5 - Collections

For deep copy (clone), you can use :

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

but there may be some concerns about the performance.

Solution 6 - Collections

This solution should work:

  List list1 = [1,2,3,4]; 
  
  List list2 = list1.map((element)=>element).toList();

It's for a list but should work the same for a map etc, remember to add to list if its a list at the end

Solution 7 - Collections

Map.from() only works for 1D map.

To copy multi dimensional map without reference in dart use following method


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

Solution 8 - Collections

Best solution for me:

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

Solution 9 - Collections

This was my solution. I hope it can help someone.

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

Solution 10 - Collections

To copy Map> filtered;

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

Solution 11 - Collections

There is no 100% bullet proof way of making an exact isolated copy, but the answer from Manish Dhruw is pretty good. However, it will only work for Maps containing simple variable types and nested Maps.

To extend it to also work with other common collections, such as List and Set, and combinations of them, you could use something like the code below.

You don't really need the DeepCopyable class, but it would be useful if you want to easily make your own classes "deep-copyable" with these functions.

abstract class DeepCopyable{
  T deepCopy<T>();
}

List<T> listDeepCopy<T>(List list){
  List<T> newList = List<T>();

  list.forEach((value) {
    newList.add(
      value is Map ? mapDeepCopy(value) :
      value is List ? listDeepCopy(value) :
      value is Set ? setDeepCopy(value) :
      value is DeepCopyable ? value.deepCopy() :
      value
    );
  });

  return newList;
}

Set<T> setDeepCopy<T>(Set s){
  Set<T> newSet = Set<T>();

  s.forEach((value) {
    newSet.add(
      value is Map ? mapDeepCopy(value) :
      value is List ? listDeepCopy(value) :
      value is Set ? setDeepCopy(value) :
      value is DeepCopyable ? value.deepCopy() :
      value
    );
  });

  return newSet;
}


Map<K,V> mapDeepCopy<K,V>(Map<K,V> map){
  Map<K,V> newMap = Map<K,V>();

  map.forEach((key, value){
    newMap[key] =
      value is Map ? mapDeepCopy(value) :
      value is List ? listDeepCopy(value) :
      value is Set ? setDeepCopy(value) :
      value is DeepCopyable ? value.deepCopy() :
      value;
  });

  return newMap;
}

As I mentioned, it's obviously still not 100% bullet proof - for example you will loose type information for nested collections.

Solution 12 - Collections

Method-1: Recommended

For cloning a multi-dimensional (nested) List or Map, use the json.decode() and json.encode()

List newList = json.decode(json.encode(oldList));
Map newMap = json.decode(json.encode(oldList));

Method-2:

List newList = [...oldList];
Map newMap = {...oldMap}

Method-3:

List newList = List.from(oldList);
Map newMap = Map.from(oldMap);

Method-4:

List newList = List.of(oldList);
Map newMap = Map.of(oldMap);

Method-5:

List newList = List.unmodifiable(oldList);
Map newMap = Map.unmodifiable(oldMap);

For more References:

https://www.kindacode.com/article/how-to-clone-a-list-or-map-in-dart-and-flutter/ https://coflutter.com/dart-flutter-how-to-clone-copy-a-list/

Solution 13 - Collections

List<int> a = [1,2,3];
List<int> b = a.toList(); // copy of a

Seems to work too

**Dart 2.15

Solution 14 - Collections

This was my solution,hope it works for you

class Person {
  String? name;
  int? age;
  Person(this.name, this.age);
  factory Person.clone(Person source) {
    return Person(source.name, source.age);
  }
}

final personList = [
  Person('Tom', 22),
  Person('Jane', 25),
];
final yourCopy = personList.map((p) => Person.clone(p)).toList();

Solution 15 - Collections

If you are working with dynamic typed data (aka sourced from JSON or built to encode as JSON) you can use this function to perform a deep copy:

cloneDeep(value) {
  if (value is List<dynamic>) {
    return value.map<dynamic>(
      (item) => cloneDeep(item),
    ).toList();
  } else if (value is Map) {
    return value.map<String, dynamic>(
        (key, item) => MapEntry<String, dynamic>(key, cloneDeep(item)));
  }
  return value;
}

Solution 16 - Collections

The given answer is good, but be aware of the generate constructor which is helpful if you want to "grow" a fixed length list, e.g.:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrice ChalinView Question on Stackoverflow
Solution 1 - CollectionsPatrice ChalinView Answer on Stackoverflow
Solution 2 - CollectionsShubham KumarView Answer on Stackoverflow
Solution 3 - CollectionsAbhishek KanojiaView Answer on Stackoverflow
Solution 4 - CollectionsstevenspielView Answer on Stackoverflow
Solution 5 - CollectionskarianpourView Answer on Stackoverflow
Solution 6 - CollectionsCodeMemoryView Answer on Stackoverflow
Solution 7 - CollectionsManish DhruwView Answer on Stackoverflow
Solution 8 - CollectionsSergView Answer on Stackoverflow
Solution 9 - CollectionsGtdDevView Answer on Stackoverflow
Solution 10 - CollectionssonOfWidgetsView Answer on Stackoverflow
Solution 11 - CollectionsMagnusView Answer on Stackoverflow
Solution 12 - CollectionsNiraj PhutaneView Answer on Stackoverflow
Solution 13 - CollectionsNonGrateView Answer on Stackoverflow
Solution 14 - CollectionsChuXiongView Answer on Stackoverflow
Solution 15 - CollectionsDavid K. HessView Answer on Stackoverflow
Solution 16 - CollectionsDan FieldView Answer on Stackoverflow