开发者

Flatten a list two ways: (i) using MAPCAN and (ii) using LOOP

My professor has given us a refresher assignment in clisp. One exercise is to achieve the same thing in three ways: Return a flattened list of all positive integers in a given list.

Now, there's only one way I really like doing this, using cons and recursion, but he wants me to do this using mapcan and a loop (I suspect lisp is not his first choice of language because this style of coding feels extremely resistant to the nature of lisp). I'm having a hard time work开发者_运维知识库ing out how one would do this using a loop...I need to first start a list, I suppose?

I apologize for vague language as I'm not really sure how to TALK about using a functional language to write procedurally. Following is my first attempt.

(defun posint-loop (l)  
  (loop for i in l
        do (if (listp i)  
               (posint-loop i)  
               (if (integerp i)  
                   (if (> i 0)  
                       (append i) ; this doesn't work because there's nothing to
                                  ; start appending to!
                       nil)  
                   nil))))


In order to establish a new lexical binding, use let or the with keyword of loop. In order to extend an existing list, you might want to use push; if you need the original order, you can nreverse the new list finally.

Another way would be to use the when and collect keywords of loop.

Another hint: mapcan implicitly creates a new list.


Mapcan applies a function to each element of a list, expecting the function to return a list, and then concatenates those resulting lists together. To apply it to this problem, you just need to process each element of the toplevel list. If the element is a list, then you need to process it recursively. If it's not, then you either need to return an empty list (which will add no elements to the final result) or a list of just that element (which will add just that element to the final result):

(defun flatten2 (list)
  (mapcan (lambda (x)
            (cond
             ((listp x) (flatten2 x))
             ((and (integerp x) (plusp x)) (list x))
             (t '())))
          list))

(flatten2 '((a 1 -4) (3 5 c) 42 0))
;=> (1 3 5 42)

With loop, you can do just about the same thing with the recognition that (mapcan f list) is functionally equivalent to (loop for x in list nconc (funcall f x)). With that in mind, we have:

(defun flatten3 (list)
  (loop for x in list
        nconc (cond 
               ((listp x) (flatten3 x))
               ((and (integerp x) (plusp x)) (list x))
               (t '()))))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜