Racket ISL如何用foldr结合local/lambda单次遍历求偶数平方
基于foldr的单次遍历偶数平方函数实现
你原先用map+filter组合的实现逻辑正确,但确实会对列表做两次遍历:第一次遍历全表筛选出所有偶数生成中间列表,第二次遍历中间列表对每个偶数做平方运算。要实现单次遍历、不对奇数做冗余平方计算的需求,直接用foldr在折叠步骤中同时完成判断、计算、拼接三个动作即可,完全符合Racket ISL的语法要求。
实现思路
foldr作为右折叠函数,会逐个处理列表中的每个元素,每一步拿到当前处理的元素和后续元素处理完成后的结果列表:
- 如果当前元素是偶数:计算它的平方,把平方值通过
cons拼到结果列表的头部 - 如果当前元素是奇数:直接跳过,不执行任何平方计算,直接返回后续结果列表
整个过程只遍历原列表一次,没有中间列表生成,所有非偶数元素完全不会触发平方运算。
代码实现
lambda版本(最简洁)
直接在foldr参数位置写匿名处理函数,不需要额外的内部定义:
; even-squares-only : [List-of Number] -> [List-of Number] ; 返回输入列表中所有偶数的平方,单次遍历无冗余计算 (define (even-squares-only lon) (foldr (λ (current rest-res) (if (even? current) (cons (sqr current) rest-res) rest-res)) '() lon))
local版本(适合逻辑更复杂的场景)
如果后续要扩展处理逻辑,可以用local把单步处理逻辑封装成内部命名函数,可读性更强:
; even-squares-only : [List-of Number] -> [List-of Number] ; 返回输入列表中所有偶数的平方,单次遍历无冗余计算 (define (even-squares-only lon) (local (; 单步处理:判断当前元素是否为偶数,是则拼接平方值到结果,否则跳过 (define (deal-current current rest-res) (if (even? current) (cons (sqr current) rest-res) rest-res))) (foldr deal-current '() lon)))
实现特性
- 输出结果和原
map+filter实现完全一致:右折叠的处理顺序保证了偶数的相对顺序和原列表一致,比如输入(list 1 2 3 4 5 6)时,两个版本的返回值都是(list 4 16 36) - 无冗余计算:所有奇数都不会执行
sqr运算,也不会生成额外的中间过滤列表 - 遍历效率更高:仅对原列表做一次完整遍历,时间复杂度和原实现同为O(n),但常数项更低
内容的提问来源于stack exchange,提问作者user19636979
相关产品推荐
相关产品推荐

