Flutter:解决向Map列表插入元素时的索引越界问题
问题
我有一个名为products的FireStore集合,文档包含name、price、category等产品数据,结构如下:
[ { "name": "Milk Shake Strawberry", "price": "250", "category": "Drinks", "categoryID": 1234 }, { "name": "Swiss Roll", "price": "150", "category": "Cake", "categoryID": 1235 } ]
通过以下代码将产品数据映射为列表:
List<Map<String, dynamic>?>? productItemsData = snapshots.data?.docs .map((e) => e.data() as Map<String, dynamic>?) .toList();
另外还有分类数据,结构如下:
[ { "index": "0", "categoryName": "Drinks", "categoryID": 1234 }, { "index": "1", "categoryName": "Cake", "categoryID": 1235 } ]
映射分类数据的代码:
List<Map<String, dynamic>?>? categoryData= snapshotCat.data?.docs .map((e) => e.data() as Map<String, dynamic>?) .toList();
之后用两层for循环将产品按分类的index插入到sortedProductItemsData列表中:
for (var doc in categoryData!) { Map<String, dynamic> data = doc as Map<String, dynamic>; for (var product in productItemsData!) { Map<String, dynamic> productData = product as Map<String, dynamic>; if (productData["category"] == data["name"]) { sortedProductItemsData?.insert(data["index"], productData); break; } } }
现在遇到的问题是:当要插入的index值大于sortedProductItemsData当前的元素长度时,会抛出错误:
Invalid value: Not in inclusive range 0..5: 8
比如列表仅有2个元素时,尝试插入到索引8的位置就会触发该错误,请问如何避免这个问题?
解决方案
方法1:修正插入索引至有效范围
Dart的List.insert()方法允许插入的索引范围是0到list.length(包含两端),如果目标索引超出这个范围,直接改为插入到列表末尾(即list.length位置)。同时注意将分类数据中的字符串类型index转为整数,避免类型错误。
修改后的代码:
for (var doc in categoryData!) { if (doc == null) continue; Map<String, dynamic> data = doc as Map<String, dynamic>; // 将字符串index转为整数 int targetIndex = int.parse(data["index"]); for (var product in productItemsData!) { if (product == null) continue; Map<String, dynamic> productData = product as Map<String, dynamic>; if (productData["category"] == data["name"]) { if (sortedProductItemsData != null) { // 计算合法的插入位置:不超过当前列表长度 int validIndex = targetIndex <= sortedProductItemsData.length ? targetIndex : sortedProductItemsData.length; sortedProductItemsData.insert(validIndex, productData); } break; } } }
方法2:先分组再按分类排序(更高效)
嵌套循环+插入的方式效率较低,且容易出现索引问题,推荐先按分类分组产品,再按分类的index排序后依次拼接:
// 1. 将产品按分类名称分组 Map<String, List<Map<String, dynamic>>> productGroups = {}; for (var product in productItemsData!) { if (product == null) continue; String category = product["category"]; productGroups.putIfAbsent(category, () => []).add(product); } // 2. 将分类数据按index(整数)排序 categoryData?.sort((a, b) { if (a == null || b == null) return 0; int indexA = int.parse(a["index"]); int indexB = int.parse(b["index"]); return indexA.compareTo(indexB); }); // 3. 按排序后的分类顺序拼接产品列表 List<Map<String, dynamic>> sortedProductItemsData = []; for (var category in categoryData!) { if (category == null) continue; String categoryName = category["categoryName"]; sortedProductItemsData.addAll(productGroups[categoryName] ?? []); }
额外提示
- 避免使用强制解包(
!),添加空值判断可以减少空指针异常的风险 - 分类数据中的
index是字符串类型,必须转为整数后再排序,否则会出现"10"排在"2"前面的字符串排序错误
内容的提问来源于stack exchange,提问作者Sameera Tennakoon
相关产品推荐
相关产品推荐

