我正在使用car& amp ;;复制球拍的长度功能。 cdr比较两个列表的长度并返回两个中较短的一个。
简单的长度函数是:
(define length
(lambda (list)
(if (null? list)
0
(+ 1 (length (cdr list))))))
当用于比较两个列表时
(define short
(lambda (list1 list2)
(if (<= (length list1) (length list2))
list1
list2)))
> (short '(a b c) '(1 2 3 4 5 6 7))
将返回&#39;(a b c)。
然而,这种方法是无效的,特别是当一个列表比另一个列表长得多时,因为它会在返回较短的列表之前迭代两个列表。
我有一个更有效的方法如下。但是我想知道是否有更有效/替代的方法来获得更短的长度而不检查两个列表的结尾。也许通过递归方式与car / cdr同时遍历列表,直到较短的列表首先到达它的结尾。
(define shorter?
(lambda (list1 list2)
(and (not (null? list2))
(or (null? list1)
(shorter? (cdr list1) (cdr list2))))))
(define shorter
(lambda (list1 list2)
(if (shorter? list2 list1)
list2
list1)))
答案 0 :(得分:2)
您的shorter?
程序已尽可能高效 - and
和or
特殊表单都会短路,并且会在任何值时停止评估表达式的结果为true
(适用于or
特殊表单)或false
(适用于and
特殊表单)。因此,只要其中一个列表达到null
,递归就会停止。您的shorter?
实施与此相同且效率相同:
(define shorter?
(lambda (list1 list2)
(cond ((null? list2) #f)
((null? list1) #t)
(else (shorter? (cdr list1) (cdr list2))))))
如果你想要一个更紧凑的解决方案,你可以将两个程序放在一个程序中,使用一个名为let
(如另一个答案中所示)或内部帮助程序,两者都是等效的。我将演示后一种方法:
(define (shorter lst1 lst2)
(define (shorter-list list1 list2)
(cond ((null? list2) lst2)
((null? list1) lst1)
(else (shorter-list (cdr list1) (cdr list2)))))
(shorter-list lst1 lst2))
答案 1 :(得分:2)
名为let&#39;方法提供了易于理解的代码。评论提供了解释:
(define (shorter l1 l2)
(let loop ((al l2) ; start with both full lists
(bl l2))
(cond
[(empty? al) l1] ; if al finishes, return l1 and end;
[(empty? bl) l2] ; if bl finishes, return l2 and end;
[else
(loop (cdr al) (cdr bl))] ; else loop again with cdr of lists;
)))
当岸上人员名单完成时,此功能将结束,并且不会不必要地持续到更长的列表结束。
答案 2 :(得分:-1)
我建议这样开始:
(define (shorter list-1 list-2) (shorter-loop list-1 list-2 list-1 list-2))
然后
(define (shorter-loop list-1 list-2 result-1 result-2)
;;
)
辅助函数short-loop同时向下递归list-1和list-2。如果list-1变为null,则返回result-1,如果list-2返回null,则返回result-2。