在Dart中克隆列表,地图或集合


Answers:


93

1,2clone()在Java中的使用非常棘手且值得商question 。实际上,是拷贝构造函数和针对的飞镖,和类型都有一个名为constructor名为执行一个浅拷贝; 例如,鉴于这些声明clone()ListMapSet.from()

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

您可以这样使用.from()

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

请注意,List.from()更普遍地接受迭代器,而不只是接受List

为了完整起见,我应该提到dart:html Node该类定义了clone()方法。


1 J. Bloch,“有效的Java ”,第二版,第11条
。2 B. Venners,“ Josh Bloch谈设计:复制构造器与克隆”,2002年。从这里引用3。从文章引用:

如果您已经阅读了我书中有关克隆的内容,尤其是您在两行之间阅读的话,您会知道我认为克隆已被严重打破。---布洛克

3 Dart Issue#6459,克隆instance(object)


8
Josh Bloch实际上参与了Dart collections API的一些早期设计。老面试
格雷格·劳

3
.from()和.addAll()并不是真正的克隆。他们在新的地图/列表/集合中添加参考。例如:Map map1 = {'一个':{'名称':1},'两个':{'名称':2},'三个':[{'a':{'A':1,'B ':2},'b':{'A':3,'B':4}}]}}; 地图map2 =新Map.from(map1); map2 ['two'] ['name'] = 4; 更改map2 ['two'] ['name']之后,map1也进行了更改
kzhdev 2014年

1
对。.from()是一个浅表副本构造函数。明确地说,我从未说过.from()执行克隆操作。我写的clone()是一种复制构造函数。
Patrice Chalin

1
请记住,如果您知道原稿的类型ListList<E>.of()可能会更好。
Michael Pfaff

27

对于列表和集合,我通常使用

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

需要说明的,如@kzhdev提到,是addAll()from()

[不要]真正地克隆。他们在新的地图/列表/集合中添加参考。

通常我可以,但是我会记住这一点。



9

使用新版本的飞镖,克隆地图或列表变得非常容易。您可以尝试使用此方法对List和Map进行深层克隆。

清单

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

对于地图

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

对于集合

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

我希望有人能对此有所帮助。


它可以与Sets一起使用吗?
funder7 '20

1
@ funder7是的,这也适用于Set。设置set1 = {1,2,3,}; 设置s = {... set1};
Shubham Kumar

但是我尝试使用它,但出现一个错误:{... set1}正在返回列表!我做错事情了?也许这是一个Beta功能?我正在使用稳定的渠道
funder7''20

1
@ funder7当我在dartpad中运行相同的代码时,它工作正常。看到这里imgur.com/JQkWZJS
Shubham Kumar

哇,超级简单。谢谢
Yash

6

对于深度复制(克隆),可以使用:

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

但是可能会对性能有所担心。


1
我不完全理解为什么此答复被否决,因为它确实具有某些优势。是的,会有一些性能问题,但它确实会使列表成为COPIES,而不仅仅是复制链接到它们。所以,我请您投票
康斯坦丁(Konstantin),

仅当只有原始属性时,您的答案才有效。想象一下,您有吸气剂/设置器/功能。json.decode-> encode将打破这一切,伙计
qiAlex

@qiAlex很明显,但这是某人可以选择的方式,伙计。很多时候,当您要克隆和对象时,它包含基元。克隆功能意味着什么!
karianpour

6

该解决方案应该起作用:

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

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

它用于列表,但对于地图等应相同,如果列表末尾请记住要添加到列表


5

Map.from()仅适用于一维地图。

若要在飞镖中复制没有参考的多维地图,请使用以下方法


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


4

最适合我的解决方案:

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

如果您在要复制的列表/地图/集中使用DateTime,则此方法不起作用。
Swift

2

这是我的解决方案。我希望它可以帮助某人。

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


0

复制Map <String,List>过滤;

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

-1

给定的答案很好,但是请注意generate构造器,如果您要“增长”固定长度的列表,这将很有帮助,例如:

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);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.