Dart实现列表元素按Map键匹配分组时运行结果不符合预期
问题排查与修正
问题复现
现有一个所有键对应初始值为空列表的Map,以及一个存储多类数据的列表,需求是遍历数据列表,将与Map键匹配的元素添加到对应键的值列表中。
初始实现代码:
void main() { List list = []; var maps= { 'A' : [], 'B' : [], 'C' : [], }; List y = ['A','B','C','A','B','C']; maps.forEach((key,values){ List temp =[]; for (var i in y){ if(key == i) { list.add(i); } temp = list; } maps[key] = temp; list.clear(); print(maps); }); }
代码实际运行输出:
{A: [], B: [], C: []}
预期输出:
{A: [A,A], B: [B,B], C: [C,C]}
错误原因
- 核心错误:Dart中
List是引用类型,代码中temp = list只是让temp变量指向了list的内存地址,没有复制列表内容,后续执行list.clear()时,temp指向的同一块内存的内容会被同步清空,最终Map里所有键对应的值都是空列表。 - 逻辑冗余:嵌套遍历效率极低,遍历Map每个键时都全量扫描一次数据列表,时间复杂度是O(n*m),完全可以优化到O(n)。
- 无效代码:开头定义的
List temp = []会被后续的temp = list直接覆盖,没有任何实际作用。
修正代码
推荐直接遍历待分类的数据列表,将元素直接追加到Map对应键的列表中,逻辑简洁且没有引用问题:
void main() { var maps = { 'A': [], 'B': [], 'C': [], }; List y = ['A', 'B', 'C', 'A', 'B', 'C']; for (final item in y) { // 判断item是Map的合法键后直接追加到对应列表 maps[item]?.add(item); } print(maps); // 输出:{A: [A, A], B: [B, B], C: [C, C]} }
如果需要保留原有嵌套遍历的写法,只需要在赋值时复制列表内容,不要直接传递引用即可(不推荐,效率更低):
void main() { List list = []; var maps= { 'A' : [], 'B' : [], 'C' : [], }; List y = ['A','B','C','A','B','C']; maps.forEach((key,values){ list.clear(); for (var i in y){ if(key == i) { list.add(i); } } // 使用List.from创建新的列表实例,复制list的内容 maps[key] = List.from(list); }); print(maps); }
内容的提问来源于stack exchange,提问作者Marco Andrade
相关产品推荐
相关产品推荐

