如何使用map和where函数替代代码中的for循环实现相同功能
实现方案
函数语义与调用顺序
map和where是函数式编程里的通用集合操作函数,语义固定,不要搞混调用顺序:
where:过滤函数,入参是返回布尔值的判断条件,输出符合条件的元素集合,对应原for循环里的if判断分支map:转换函数,入参是元素转换规则,输出和输入元素一一对应的新值集合,对应原for循环里对符合条件的元素做处理、生成类实例的逻辑
注意:必须先调用
where做过滤,再调用map做转换。顺序颠倒会先对所有元素(包括不符合条件的无效元素)执行实例化逻辑,既会触发不必要的实例化报错,也会造成性能浪费。
代码对比
先给出可正常运行的原始for循环参考逻辑(以最常出现该问题的Dart场景为例,其他支持map/where的语言逻辑完全一致):
List<Item> result = []; for (var rawData in rawDataList) { // 第一步:过滤无效数据 if (rawData.isValid && rawData.type == expectType) { // 第二步:对有效数据实例化目标类 Item instance = Item.fromRaw(rawData); result.add(instance); } }
触发报错的常见错误写法有两种:
// 错误1:先map后where,无效数据也会被执行实例化,触发报错 var wrong1 = rawDataList.map((e) => Item.fromRaw(e)).where((e) => e.isValid && e.type == expectType).toList(); // 错误2:map内用代码块写法时漏写return,生成的集合全是null var wrong2 = rawDataList.where((e) => e.isValid && e.type == expectType).map((e) { Item.fromRaw(e); // 大括号代码块不会自动返回值,必须手动写return }).toList();
和原for循环逻辑完全一致的正确写法:
List<Item> correctResult = rawDataList .where((raw) => raw.isValid && raw.type == expectType) // 完全对应原循环的if判断条件 .map((validRaw) => Item.fromRaw(validRaw)) // 对过滤后的有效数据执行实例化,箭头函数自动返回实例 .toList(); // 惰性求值语言必须加该方法,将迭代器转为实际集合,拿到和原循环一致的输出
避坑要点
where的回调只能返回布尔值,不要在里面写实例化、值转换逻辑map是1:1转换,输入N个元素就会输出N个元素,不要在里面写过滤逻辑- 支持惰性求值的语言(Dart、Kotlin、JavaScript、Python3等)中,
map/where默认返回迭代器对象,不会立刻执行内部逻辑,必须调用toList()/collect()这类聚合方法,才会真正执行过滤和转换 - 如果
map内用大括号包裹多行实例化逻辑,必须手动写return返回生成的实例,箭头函数写法会自动返回箭头后的值,不需要额外写return
内容的提问来源于stack exchange,提问作者Lui
相关产品推荐
相关产品推荐

