6

有时我需要遍历列表中的连续对。我现在的做法是

(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 这样的内置函数可以让我得到这个?

4

2 回答 2

7

AFAIK,没有内置功能可以做你想做的事。您可以尝试将某些东西与 放在一起maplist,但我的第一直觉也是伸手loop去拿。

不过,只是对您所拥有的内容进行了一些说明。首先,(not (null foo))等价foo于 CL,因为非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 作为其结果的最后一个元素,而不是在此之前结束)。

于 2012-08-10T17:04:23.363 回答
3

我相信 Paul Graham 在 OnLisp 中有一个名为 map-tuple 的函数来执行此操作。它可以按 cdr、cddr 或任何您喜欢的方式在列表中向下移动。这是它的注释版本。它使用他的照应 if 宏 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)))))
于 2012-08-23T06:43:31.597 回答