Flutter中如何用Equatable包比较含无序列表的Question对象?
问题描述
我创建了一个继承Equatable的Question类,类里有个名为answers的List属性(长度固定为4,元素是String类型)。我想让两个answers元素相同但顺序不同的Question对象被判定为相等,但直接在重写的props里返回[answers]做不到这一点。相关代码和JSON响应示例如下:
Question类代码
@immutable /// Question class to model the api response: it will be /// used in the Presentation layer class Question extends Equatable { final String question; final String correctAnswer; final List<dynamic>? answers; const Question({ required this.question, required this.correctAnswer, this.answers, }); @override List<Object?> get props => [ question, correctAnswer, answers, ]; }
QuestionResponseModel类代码
@immutable class QuestionResponseModel extends Question { final List<dynamic> incorrectAnswers; const QuestionResponseModel({ required correctAnswer, required question, required this.incorrectAnswers, }) : super( correctAnswer: correctAnswer, question: question, ); factory QuestionResponseModel.fromJson(Map<String, dynamic> map) { return QuestionResponseModel( question: map['question'] ?? '', correctAnswer: map['correct_answer'] ?? '', incorrectAnswers: map['incorrect_answers'] ?? [], ); } Question toEntity() { return Question( question: question, correctAnswer: correctAnswer, answers: incorrectAnswers ..add(correctAnswer) ..shuffle()); } @override List<Object?> get props => [ question, correctAnswer, incorrectAnswers, ]; }
JSON响应示例
{ "response_code": 0, "results": [ { "category": "Entertainment: Books", "type": "multiple", "difficulty": "medium", "question": "What is the fourth book of the Old Testament?", "correct_answer": "Numbers", "incorrect_answers": [ "Genesis", "Exodus", "Leviticus" ] } ] }
解决方法
Equatable对List的相等判断是顺序敏感的——只有两个List的元素顺序完全一致,才会被判定为相等,这就是直接返回answers无法满足需求的原因。要实现无序元素的相等判断,有两种可行方案:
方案1:返回排序后的answers列表
在props里返回排序后的answers,这样不管原始顺序如何,只要元素相同,排序后的结果就一致,Equatable就能正确判定相等。
修改Question类的props:
@override List<Object?> get props => [ question, correctAnswer, // 先转成String列表再排序,避免dynamic类型导致的问题 answers?.map((item) => item.toString()).toList()..sort(), ];
如果能确定answers里的元素都是String类型,可以简化成answers?.toList()..sort()。
方案2:将answers转为Set
Set是无序且不允许重复的集合,只要两个Set包含的元素完全相同,就会被判定为相等,刚好适配你的场景(answers是4个不重复的选项)。
修改Question类的props:
@override List<Object?> get props => [ question, correctAnswer, answers != null ? Set.from(answers!) : null, ];
额外优化提示
- 把Question类里的
List<dynamic>? answers改成List<String>? answers,类型更明确,避免后续处理时的类型问题——毕竟你的JSON返回的答案都是字符串。 - QuestionResponseModel的
toEntity()方法里,incorrectAnswers..add(correctAnswer)会修改原incorrectAnswers列表(List是引用类型),建议创建新列表再操作,避免产生副作用:
Question toEntity() { final allAnswers = List<String>.from(incorrectAnswers) ..add(correctAnswer) ..shuffle(); return Question( question: question, correctAnswer: correctAnswer, answers: allAnswers, ); }
内容的提问来源于stack exchange,提问作者Andi
相关产品推荐
相关产品推荐

