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

- 15,440
- 7
- 33
- 44
-
2I was going to add my own answer here but instead I turned it into an article: [Cloning lists, maps, and sets in Dart](https://suragch.medium.com/cloning-lists-maps-and-sets-in-dart-d0fc3d6a570a?sk=d524c3b1aa8d3565c2149991cc7a2072) – Suragch Aug 26 '21 at 11:24
18 Answers
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

- 1
- 1

- 15,440
- 7
- 33
- 44
-
11Josh Bloch was actually involved in some of the early design of the Dart collections API. [Old interview](https://www.youtube.com/watch?v=wmsVHdllIPM). – Greg Lowe Feb 17 '14 at 22:05
-
4The .from() and .addAll() not really make a clone. They add a reference in the new Map/List/Set. For example: Map map1 = { 'one': {'name': 1}, 'two': {'name': 2}, 'three': [{ 'a': { 'A': 1, 'B': 2 }, 'b': { 'A': 3, 'B': 4 } }] }; Map map2 = new Map.from(map1); map2['two']['name'] = 4; After changing map2['two']['name'], map1 changed as well – kzhdev Apr 17 '14 at 21:41
-
3Right. `.from()` is a _shallow_ copy constructor. Just to be clear, I never said that `.from()` performed a clone operation. What I wrote was the `clone()` was a kind of copy constructor. – Patrice Chalin Apr 20 '14 at 17:07
-
2Keep in mind that if you know the type of the original `List`, `List
.of()` might be better. – Michael Pfaff Sep 29 '19 at 14:58
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.

- 2,171
- 1
- 13
- 22
-
2@funder7 Yes, this works with Set also. Set set1 = {1,2,3,}; Set s = {...set1}; – Shubham Kumar Dec 28 '20 at 12:50
-
But I've tried to use it and I've got an error: {...set1} was returning a list! I did something wrong? Or maybe it's a beta feature? I'm using the stable channel – funder7 Dec 30 '20 at 20:18
-
1@funder7 It worked fine when i run the same same code in dartpad. see here https://imgur.com/JQkWZJS – Shubham Kumar Jan 05 '21 at 10:31
-
8This will not clone a list of objects! The list will contain references to each object. https://dartpad.dartlang.org/?41547dfffef02aeb34e14c1123adf72a – genericUser Jun 05 '22 at 14:23
-
2
-
2Yes it is just a swallow copy. The references of each object item will be same. – MJ Studio Sep 22 '22 at 07:03
-
Set setA = {obj1, obj2, obj3}; Set setB = {...setA}; ==> this is same and not a clone – Ali Bagheri Jan 30 '23 at 09:41
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

- 839
- 8
- 7
-
16Note that this will not clone a list of objects. The list will contain references. – ZeroNine May 18 '20 at 02:43
-
3
-
Unfortunately it will return a List, so it's not usable with Sets either – funder7 Dec 27 '20 at 21:43
-
1@funder It's a `List` because of the square brackets. The general technique works with `Set`s or `Map`s: `{...set}` or `{...map}`. – jamesdlin Oct 22 '21 at 23:41
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.

- 5,775
- 13
- 60
- 89
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.

- 28,155
- 10
- 49
- 57

- 704
- 5
- 15
-
2I don't completely understand why this reply was downvoted as it really has some advantage. Yes, there will be some performance issues but it will really make COPIES of lists inside, not just copying a link to them. So I'll you an upvote – Konstantin Oct 09 '19 at 13:44
-
1Your answer will work only if there are only primitive attributes. Imagine that you have getters/setters/functions. json.decode->encode will break this all, dude – qiAlex Nov 18 '19 at 00:09
-
3@qiAlex that is obvious, but it is a way that someone can choose, dude. Many times when you want to clone and object that is the case that it contain primitives. What does is mean to clone a function! – karianpour Nov 18 '19 at 14:23
-
@qiAlex Just add `fromJson` to your source class, then for a list of objects: `final copy = List
.from(json.decode(json.encode(src)).map((e) => SrcClass.fromJson(e)).toList()`. – BeniaminoBaggins Mar 14 '23 at 19:26
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

- 5,564
- 4
- 28
- 39

- 839
- 7
- 10
-
Ah, thanks, so we can do this `list1.map((element)=>element.copy()).toList();` if our classes have a `copy` method defined and now get a truly deep copy. – Richard Apr 25 '22 at 19:48
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/

- 1,586
- 1
- 12
- 10
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;
}

- 753
- 9
- 18
-
While this works, it does not keep the type information of nested maps. It seems it's not possible to do that, except for maybe using reflection... – Magnus Mar 04 '22 at 08:36
Best solution for me:
List temp = {1,2,3,4}
List platforms = json.decode(json.encode(parent.platforms));

- 17,954
- 24
- 89
- 100

- 51
- 9
-
1This doesn't work if you use DateTime in the list/map/set that you're copying. – Swift Apr 12 '20 at 22:37
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,
);}

- 748
- 6
- 14
To copy Map<String, List> filtered;
var filteredNewCopy = filtered.map((key, value) => MapEntry(key, [...value]));

- 139
- 1
- 7
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.

- 17,157
- 19
- 104
- 189
List<int> a = [1,2,3];
List<int> b = a.toList(); // copy of a
Seems to work too
**Dart 2.15

- 862
- 9
- 22
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();

- 1
- 2
-
Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Apr 07 '22 at 18:57
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;
}

- 16,632
- 2
- 49
- 73
best solution is use of toMap()
and fromMap()
for classes.
class A {
String title;
A(Map<String, Object> map){ // fromMap() or fromJson()
title= map['title'];
}
Map<String, Object> toMap(){
final res = <String, Object>{};
res['title'] = title;
return res;
}
}

- 3,068
- 27
- 28
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);
}

- 20,885
- 5
- 55
- 71