Dart中如何实现类似SQL多字段GROUP BY的Map列表分组聚合?
Dart 实现多字段分组聚合求和
你可以直接通过给groupBy传入复合分组键的方式实现多字段分组,不需要额外引入其他工具,完整实现如下:
import 'package:collection/collection.dart'; void main() { var data = [ {"day": 'Monday', "weather": 'warm', 'ctd': 20, 'other':'a'}, {"day": 'Monday', "weather": 'warm', 'ctd': 15, 'other':'b'}, {"day": 'Tuesday', "weather": 'cold', 'ctd': 25, 'other':'c'}, {"day": 'Tuesday', "weather": 'cold', 'ctd': 35, 'other':'d'}, ]; // 以day和weather两个字段作为联合分组键 final groupMap = groupBy( data, (Map item) => (item['day'], item['weather']), ); // 对每个分组做ctd字段求和,再转换为目标列表结构 final result = groupMap.entries.map((entry) { final (day, weather) = entry.key; final totalCtd = entry.value.fold<int>( 0, (pre, cur) => pre + (cur['ctd'] as int), ); return { "day": day, "weather": weather, "ctd": totalCtd, }; }).toList(); print(result); // 输出结果和预期完全一致: // [{day: Monday, weather: warm, ctd: 35}, {day: Tuesday, weather: cold, ctd: 60}] }
低版本兼容说明
如果你的项目使用Dart 3.0以下版本,不支持Record(记录)语法,可以用拼接字符串作为复合分组键,写法如下:
final groupMap = groupBy( data, (Map item) => "${item['day']}||${item['weather']}", ); final result = groupMap.entries.map((entry) { final keyParts = entry.key.split('||'); final totalCtd = entry.value.fold<int>( 0, (pre, cur) => pre + (cur['ctd'] as int), ); return { "day": keyParts[0], "weather": keyParts[1], "ctd": totalCtd, }; }).toList();
注意拼接字符串时选择一个不会出现在分组字段值里的分隔符,避免键冲突。
原有写法问题说明
你之前的尝试存在两个问题:
- 分组键仅传入了
day单个字段,没有将weather纳入分组维度,无法区分同日期不同天气的分组 - 聚合后直接返回了「分组键:ctd求和值」的Map结构,没有组装分组维度的字段,也没有转换为要求的List格式
如果后续需要增加分组字段,只需要在复合键里追加对应字段即可;如果需要实现计数、求平均值等其他聚合逻辑,修改fold内的计算规则就能实现。
内容的提问来源于stack exchange,提问作者José Luis Zarabanda Díaz
相关产品推荐
相关产品推荐

