Flutter中基于两个列表按条件生成selectedBooks列表的问题排查
你遇到的问题根源在于条件判断的逻辑错误:allowedBooks.contains(book.id)这行代码完全不符合预期的判断逻辑。
为什么会出错?
allowedBooks是一个Book对象的列表,List.contains()方法默认是用来判断对象是否存在于列表中的——它会比较对象的引用(如果你的Book类重写了==方法,就按重写的规则比较)。但你这里传入的是book.id(一个数字),和列表里的Book对象类型完全不匹配,所以这个判断永远会返回false,最终导致所有生成的Book实例的isActive都是false。
修复方案
我们需要调整判断逻辑,改成检查allowedBooks中是否存在id与当前book.id一致的对象,这里有两种常用的实现方式:
方式一:使用any()方法直接判断
这是最直观的写法,适合数据量不大的场景:
selectedBooks = availableBooks .map((book) => allowedBooks.any((allowedBook) => allowedBook.id == book.id) ? Book(id: book.id, isActive: true, name: book.name) : Book(id: book.id, isActive: false, name: book.name)) .toList();
any()方法会遍历allowedBooks列表,只要找到一个id匹配的元素,就返回true,这样就能正确触发isActive: true的分支。
方式二:先提取允许的id到集合(性能更优)
如果你的allowedBooks列表元素较多,反复用any()遍历会有性能损耗,建议先把所有允许的id提取到一个Set中(Set的查询效率是O(1)):
// 先把允许的book id提取到Set里 final allowedBookIds = allowedBooks.map((book) => book.id).toSet(); selectedBooks = availableBooks .map((book) => allowedBookIds.contains(book.id) ? Book(id: book.id, isActive: true, name: book.name) : Book(id: book.id, isActive: false, name: book.name)) .toList();
这种写法在列表元素较多时,性能会比直接用any()好很多。
额外优化小建议
如果你的Book类是不可变的,其实还可以进一步优化:当book在允许列表中时,直接复用allowedBooks里对应的实例,避免重复创建对象。比如:
final allowedBookMap = {for (var book in allowedBooks) book.id: book}; selectedBooks = availableBooks .map((book) => allowedBookMap[book.id] ?? book) .toList();
这样如果有匹配的id,就直接用允许列表里的Book实例(它的isActive已经是true),否则就用原有的实例,代码更简洁高效。
内容的提问来源于stack exchange,提问作者Giulia

