Dart中如何移除列表中首个匹配特定属性的对象?
问题
根据Dart/Flutter文档,List.remove()可以移除列表中首个匹配的元素,removeWhere()也可用于移除对象。我尝试编写代码移除列表中首个属性匹配特定对象的元素,但调用testList.remove(z)返回false,目标对象未被移除;直接移除原对象a却能成功。以下是我的代码及运行输出:
代码示例
class Test { bool? a; bool? b; String? ex; String? yz; Test({ this.a, this.b, this.ex, this.yz, }); Map<String, dynamic> toJson() => { "a": a, "b": b, "ex": ex, "yz": yz, }; Test copy({bool? a, bool? b, String? ex, String? yz}){ return Test( a : a ?? this.a, b : b ?? this.b, ex : ex ?? this.ex, yz : yz ?? this.yz, ); } } void main() { Test a = Test( a : true, b : false, ex : "S001", yz : "plus" ); Test b = Test( a : false, b : true, ex : "S001", yz : "plus" ); Test c = Test( a : true, b : true, ex : "S001", yz : "plus" ); Test d = Test( a : false, b : false, ex : "S001", yz : "plus" ); Test z = a.copy(); // 希望移除列表中属性与a匹配的对象 List<Test> testList = [a, b, c, d]; for(var item in testList){ print(item.toJson()); } // [a, b, c, d] var result = testList.remove(z); print(result); for(var item in testList){ print(item.toJson()); } }
运行输出
{a: true, b: false, ex: S001, yz: plus} {a: false, b: true, ex: S001, yz: plus} {a: true, b: true, ex: S001, yz: plus} {a: false, b: false, ex: S001, yz: plus} false {a: true, b: false, ex: S001, yz: plus} {a: false, b: true, ex: S001, yz: plus} {a: true, b: true, ex: S001, yz: plus} {a: false, b: false, ex: S001, yz: plus}
请问哪里操作有误?或有其他方法可实现该需求?
原因分析
Dart中List.remove()默认用对象引用相等性(即==运算符默认比较内存地址)匹配元素。你通过a.copy()创建的z是全新对象,虽然属性和a完全一致,但它和列表中的a不是同一个内存引用,所以remove(z)找不到匹配项,返回false;直接移除a时,因为列表中存在该引用,所以能成功。
解决方法
1. 重写==运算符和hashCode
让Test类支持按属性值比较相等性,这样List.remove()就能识别属性相同的对象。修改后的Test类如下:
class Test { bool? a; bool? b; String? ex; String? yz; Test({ this.a, this.b, this.ex, this.yz, }); Map<String, dynamic> toJson() => { "a": a, "b": b, "ex": ex, "yz": yz, }; Test copy({bool? a, bool? b, String? ex, String? yz}){ return Test( a : a ?? this.a, b : b ?? this.b, ex : ex ?? this.ex, yz : yz ?? this.yz, ); } // 重写==运算符,按属性比较相等性 @override bool operator ==(Object other) => identical(this, other) || other is Test && runtimeType == other.runtimeType && a == other.a && b == other.b && ex == other.ex && yz == other.yz; // 重写hashCode,确保属性相等的对象hash值一致 @override int get hashCode => Object.hash(a, b, ex, yz); }
修改后再调用testList.remove(z)即可成功移除首个属性匹配的元素。
2. 使用indexWhere+removeAt精准移除首个匹配项
无需修改类的相等性逻辑,直接通过属性条件找到首个匹配元素的索引,再移除:
// 找到首个属性与a匹配的元素索引 int targetIndex = testList.indexWhere((item) => item.a == a.a && item.b == a.b && item.ex == a.ex && item.yz == a.yz ); // 找到则移除 if (targetIndex != -1) { testList.removeAt(targetIndex); }
3. 使用removeWhere(注意:会移除所有匹配元素)
如果需要移除所有属性匹配的元素,可直接用removeWhere:
testList.removeWhere((item) => item.a == a.a && item.b == a.b && item.ex == a.ex && item.yz == a.yz );
内容的提问来源于stack exchange,提问作者kilokahn
相关产品推荐
相关产品推荐

