Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp: what's the best way to loop through consecutive pairs in a list?

Tags:

common-lisp

Sometimes I need to loop through consecutive pairs in a list. The way I do it right now is

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

I'm wondering if there is a better/built-in way to do this.

The reason I need this is sometimes I want, e.g. some function that add consecutive pairs

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

Is there any built-in function like reduce which allow me to get this?

like image 499
h__ Avatar asked Aug 10 '12 16:08

h__


2 Answers

AFAIK, there isn't a built-in function to do what you want. You could try to put something together with maplist, but my first instinct would be to reach for loop too.

Just a couple of notes on what you've got there though. First, (not (null foo)) is equivalent to foo in CL, since a non-NIL value is treated as t by boolean operations. Second, loop can destructure its arguments, meaning you can write this more elegantly as

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

The maplist version would look something like

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

which I consider less readable (this would also return NIL as the last element of its result, rather than just ending before that).

like image 52
Inaimathi Avatar answered Oct 22 '22 10:10

Inaimathi


I believe Paul Graham has a function named map-tuple in OnLisp which does this. It can move down the list by cdr, cddr, or however you please. Here is a commented version of it. It uses his anaphoric if macro 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)))))
like image 20
Chris Perkins Avatar answered Oct 22 '22 10:10

Chris Perkins