如何高效修改列表特定元素值并优化Flutter函数性能?
问题背景
我需要高效修改列表中特定元素的值,目前已编写Flutter函数findAndOperate,可对主列表内选中元素的price执行PLUS或MULTIPLICATION运算,功能符合预期,但作为新手,想了解该函数的优化方向。
测试代码
// ignore_for_file: public_member_api_docs, sort_constructors_first import 'package:flutter_test/flutter_test.dart'; void main() { test( 'find list item and apply math', () { final mockList = <Model>[ Model(id: '1', name: 'Cortado', price: 12), Model(id: '2', name: 'Caffe Latte', price: 24), Model(id: '3', name: 'Americano', price: 48), Model(id: '4', name: 'Turkish Coffee', price: 96), Model(id: '5', name: 'Filter Coffee', price: 64), Model(id: '6', name: 'Flat White', price: 128), ]; final selectItems = [mockList[0], mockList[3]]; final result = findAndOperate( mainList: mockList, selectedList: selectItems, operations: Operations.PLUS, value: 40, ); print(result); }, ); } List<Model> findAndOperate({ required double value, required Operations operations, required List<Model> mainList, required List<Model> selectedList, }) { for (final selectItem in selectedList) { for (final item in mainList) { if (item == selectItem) { final itemIndex = mainList.indexOf(item); switch (operations) { case Operations.PLUS: final changeItem = selectItem.copyWith(price: selectItem.price + value); mainList.removeAt(itemIndex); mainList.insert(itemIndex, changeItem); case Operations.MULTIPLICATION: final changeItem = selectItem.copyWith( price: selectItem.price + (selectItem.price * value), ); mainList.removeAt(itemIndex); mainList.insert(itemIndex, changeItem); } } } } return mainList; } // ignore: constant_identifier_names enum Operations { PLUS, MULTIPLICATION } class Model { Model({required this.id, required this.name, required this.price}); final String id; final String name; final double price; Model copyWith({ String? id, String? name, double? price, }) { return Model( id: id ?? this.id, name: name ?? this.name, price: price ?? this.price, ); } @override String toString() => 'MockModel(id: $id, name: $name, price: $price)'; @override bool operator ==(covariant Model other) { if (identical(this, other)) return true; return other.id == id && other.name == name && other.price == price; } @override int get hashCode => id.hashCode ^ name.hashCode ^ price.hashCode; }
运行结果
[MockModel(id: 1, name: Cortado, price: 52.0), MockModel(id: 2, name: Caffe Latte, price: 24.0), MockModel(id: 3, name: Americano, price: 48.0), MockModel(id: 4, name: Turkish Coffee, price: 136.0), MockModel(id: 5, name: Filter Coffee, price: 64.0), MockModel(id: 6, name: Flat White, price: 128.0)]
优化方向
1. 大幅提升性能:消除嵌套循环与冗余查找
当前代码用两层嵌套循环遍历选中列表和主列表,时间复杂度为O(n*m)(n为选中元素数,m为主列表长度),且找到匹配元素后又调用mainList.indexOf(item)做重复查找,完全没必要。
优化方案:先把选中元素的唯一标识id存入Set(实现O(1)查找),再遍历主列表一次完成所有修改,时间复杂度降至O(n+m):
List<Model> findAndOperate({ required double value, required Operations operations, required List<Model> mainList, required List<Model> selectedList, }) { final selectedIds = selectedList.map((e) => e.id).toSet(); return mainList.map((item) { if (!selectedIds.contains(item.id)) return item; final newPrice = switch(operations) { Operations.PLUS => item.price + value, Operations.MULTIPLICATION => item.price * (1 + value), // 简化原公式:price + price*value = price*(1+value) }; return item.copyWith(price: newPrice); }).toList(); }
2. 遵循不可变原则:避免修改原列表
当前函数直接对传入的mainList执行removeAt和insert操作,会导致原列表被意外修改,不符合Flutter偏好不可变数据的最佳实践,也容易引发难以追踪的状态bug。
优化后的代码通过map生成新列表,原列表保持不变,更安全,也适配Provider、Riverpod等状态管理框架的更新逻辑。
3. 简化运算逻辑:优化乘法公式
原乘法运算代码selectItem.price + (selectItem.price * value)可简化为selectItem.price * (1 + value),逻辑更清晰,计算效率一致。
4. 增强扩展性:用函数替代枚举(可选)
如果后续需要添加减法、除法等运算,每次修改枚举和switch会很繁琐。可以直接传入运算函数,让函数更灵活:
// 定义运算函数类型 typedef PriceOperation = double Function(double currentPrice, double value); List<Model> findAndOperate({ required double value, required PriceOperation operation, required List<Model> mainList, required List<Model> selectedList, }) { final selectedIds = selectedList.map((e) => e.id).toSet(); return mainList.map((item) { if (!selectedIds.contains(item.id)) return item; return item.copyWith(price: operation(item.price, value)); }).toList(); } // 使用示例 final addResult = findAndOperate( mainList: mockList, selectedList: selectItems, operation: (price, val) => price + val, value: 40, ); final multiplyResult = findAndOperate( mainList: mockList, selectedList: selectItems, operation: (price, val) => price * (1 + val), value: 0.5, );
5. 修复潜在匹配问题:用唯一ID判断元素
原代码用item == selectItem判断匹配,但Model的==运算符包含了price字段——如果选中元素的price已被修改,会出现匹配失败的问题。实际应该只用唯一标识id判断元素身份,和价格无关。
6. 添加边界处理(可选)
可以增加简单的边界检查,避免无意义操作:
List<Model> findAndOperate({ required double value, required Operations operations, required List<Model> mainList, required List<Model> selectedList, }) { // 空列表直接返回原列表副本 if (mainList.isEmpty || selectedList.isEmpty) return List.from(mainList); // 其他逻辑... }
内容的提问来源于stack exchange,提问作者Kaan

