SplayTreeSet重复元素问题:如何使其使用重载的equals方法?
解决SplayTreeSet重复元素问题:让集合使用自定义相等判断
问题根源
Dart的SplayTreeSet(包括通过ObservableSet.splayTreeSetFrom创建的实例)不依赖你重载的operator==和hashCode判断元素是否相等,它完全基于传入的compare比较器:当compare(a, b)返回0时,就认为a和b是同一个元素,不会重复添加;反之,哪怕两个元素的==返回true,只要compare结果不为0,就会被当成不同元素存入集合。
你的当前compare逻辑是按createTime排序,所以即使两个元素的chatRoomId相同(你的相等判断规则),只要createTime不同,compare就不会返回0,集合就会判定为不同元素,导致重复添加。而调用toSet()后重复消失,是因为普通Set(如HashSet)是用operator==和hashCode去重的,刚好符合你的判断规则。
解决方案
修改compare比较器,先按chatRoomId判断元素是否相等(返回0),再按createTime排序。有两种实现方式:
方式一:修改模型的compareTo方法
调整ChatRoomListModel的compareTo逻辑,优先比较chatRoomId:
int compareTo(ChatRoomListModel other) { // 先比较chatRoomId,相同则视为同一元素 final idComparison = messagesModel.chatRoomId.compareTo(other.messagesModel.chatRoomId); if (idComparison != 0) { // id不同时,按createTime正序排序(配合集合的倒序参数实现最终倒序) return messagesModel.createTime.compareTo(other.messagesModel.createTime); } return 0; }
集合的初始化代码保持不变:
ObservableSet<ChatRoomListModel> _latestMessages = ObservableSet.splayTreeSetFrom( ObservableSet(), compare: (a, b) => b.compareTo(a), // 保持按createTime倒序排列 );
方式二:直接在集合的compare参数中处理
无需修改模型,直接在创建集合时定义比较逻辑:
ObservableSet<ChatRoomListModel> _latestMessages = ObservableSet.splayTreeSetFrom( ObservableSet(), compare: (a, b) { // 优先判断chatRoomId是否相同,相同则返回0(视为同一元素) final idCompare = a.messagesModel.chatRoomId.compareTo(b.messagesModel.chatRoomId); if (idCompare != 0) { // id不同时,按createTime倒序排序 return b.messagesModel.createTime.compareTo(a.messagesModel.createTime); } return 0; }, );
验证
修改后,添加chatRoomId相同的元素时,compare会返回0,集合会判定为重复元素而拒绝添加;不同chatRoomId的元素则按createTime排序存入,同时contains方法也会基于compare逻辑正确返回结果。
内容的提问来源于stack exchange,提问作者DanMossa
相关产品推荐
相关产品推荐

