Common Lisp:在列表中循环连续对的最佳方法是什么?

时间:2012-08-10 16:30:33

标签: common-lisp

有时我需要遍历列表中的连续对。我现在这样做的方式是

(loop for x on lst while (not (null (cdr x)))
       (do something on (car x) and (cadr x)))

我想知道是否有更好/内置的方法来做到这一点。

我需要这个的原因有时是我想要的,例如一些添加连续对的函数

(1 2 3 4 5) ----> (3 5 7 9)

是否有像reduce那样的内置函数可以让我得到它?

2 个答案:

答案 0 :(得分:7)

AFAIK,没有内置功能可以做你想要的。您可以尝试将某些内容与maplist放在一起,但我的第一直觉也是loop

关于你到底在那里的几个笔记。首先,(not (null foo))相当于CL中的foo,因为非NIL值被布尔运算视为t。其次,loop可以解构其论点,这意味着你可以更优雅地写这个

(loop for (a b) on lst while b
      collect (+ a b))

maplist版本看起来像

(maplist 
   (lambda (rest) 
     (when (cdr rest) 
        (+ (first rest) (second rest)))
   lst)

我认为它的可读性较低(这也会将NIL作为其结果的最后一个元素返回,而不是在此之前结束)。

答案 1 :(得分:3)

我相信Paul Graham在OnLisp中有一个名为map-tuple的函数来执行此操作。它可以通过cdr,cddr在列表中向下移动,或者不管你喜欢。这是它的评论版本。如果宏 aif ,它会使用他的照应。

(defun map-tuple (someList f &optional (by #'cdr))
 "(map-tuple someList f &optional (by #'cdr))
   f is a function that takes two args, returns one val (maybe)
   the map-tuple will collect all non-nil results in a list.
    example: 
(map-tuple '(1 2 3 4 5 6) (lambda (a b) (format T \"a: ~A b:~A~%\" a b)) #'cdr) 
a: 1 b:2
a: 2 b:3
a: 3 b:4
a: 4 b:5
a: 5 b:6
a: 6 b:NIL

(map-tuple '(1 2 3 4 5 6) (lambda (a b) (format T \"a: ~A b:~A~%\" a b)) #'cddr) 
a: 1 b:2
a: 3 b:4
a: 5 b:6
"
  (cond ((null someList)
        nil)
    (T
       (aif (funcall f (car someList) (cadr someList))
          (cons it (map-tuple (funcall by someList) f by))
           (map-tuple (funcall by someList) f by)))))