我在Lisp做了一个小练习:
使用参数
test-delta
和delta
编写一个函数lst
检查lst
中连续元素之间的差异是否小于delta
。以两种方式编写函数:
- 递归地
- 使用映射函数
我以递归方式编写该函数没有问题,但我不知道应该使用哪个映射函数。所有标准映射函数一次只能使用列表中的一个元素。 reduce
也不能使用,因为我没有在连续元素之间使用某些操作。我在这里使用 的功能是什么?
答案 0 :(得分:3)
所有标准功能一次只能使用一个元素。
减少功能也不能使用 因为我没有在元素之间使用某些操作。
uselpa已经an answer显示您可以使用reduce
执行此操作,但我感到有点尴尬地将reduce
弯曲到这种情况。
在我看来,更自然地认识到标准映射函数实际上允许您使用多个列表。我首先会显示mapcar
和loop
,然后会every
,我认为这是真正的赢家。最后,为了完整起见,我还提到了maplist
。
标准mapcar
可以使用多个列表,这意味着您可以同时从两个不同的列表中获取元素。特别值得注意的是,它可能需要list
和(rest list)
。例如,
(let ((list '(1 2 3 4 5 6)))
(mapcar 'cons
list
(rest list)))
;=> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6))
您可以使用loop
执行相同的操作:
(loop
with l = '(1 2 3 4 5 6)
for a in l
for b in (rest l)
collect (cons a b))
;=> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6))
您可以使用loop
上的其他一些变体,但其中一些变体的结果较少。例如,你可以循环(a b) on list
,但是你得到一个(可能)意外的变量最终绑定:
(loop for (a b) on '(1 2 3 4 5 6)
collect (list a b))
;=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 NIL))
这类似于maplist
将为您提供的内容。
我认为这里真正的赢家将会成为every
, some
, notevery
, and notany
职能部门。与mapcar
一样,这些可以使用多个列表作为参数。这意味着您的问题可能只是:
(let ((delta 4)
(lst '(1 2 4 7 9)))
(every (lambda (x y)
(< (abs (- x y)) delta))
lst
(rest lst)))
;=> T
(let ((delta 2)
(lst '(1 2 4 7 9)))
(every (lambda (x y)
(< (abs (- x y)) delta))
lst
(rest lst)))
;=> NIL
您也可以使用maplist
执行此操作,该6 NIL
适用于列表的连续 tails ,这意味着您可以访问每个元素以及后面的元素。尽管如此,第二个loop
解决方案最终会有(maplist (lambda (tail)
(list (first tail)
(second tail)))
'(1 2 3 4 5 6))
;=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 NIL))
。 E.g:
{{1}}
答案 1 :(得分:1)
reduce
可以使用:
(defun testdelta (delta lst)
(reduce
(lambda (r e)
(if (< (abs (- r e)) delta)
e
(return-from testdelta nil)))
lst)
t)
或者,没有return-from
(但可能更慢):
(defun testdelta (delta lst)
(and
(reduce
(lambda (r e)
(and r (if (< (abs (- r e)) delta) e nil)))
lst)
t))