lisp:从单个列表构建列表列表

时间:2016-10-28 18:48:01

标签: list recursion lisp

我正在尝试列出我拥有的16个数字,并将其列入4个,4个元素的子列表,以表示魔术广场的游戏板。我创建了一个方法,可以获取列表并返回单个子列表,现在我试图递归使用此方法来构建完整的板。

我的问题是,我的initBoard无论如何返回nil,我知道其他所有方法都按预期工作。任何澄清我的错误将不胜感激!

此处还有一个示例输入列表:

(4 5 15 10 14 11 1 8 9 16 6 3 7 2 12 13)

我想要的输出是:

((4 5 15 10)(14 11 1 8)(9 16 6 3)(7 2 12 13))

(defun smallList (lst cnt)
   (cond ((>= cnt 4) nil)
   (t (cons (car lst) (smallList (cdr lst) (+ 1 cnt))))))

(defun isEmpty (lst)
   (if lst 1 -1))

(defun initBoard (lst)
   (cond ((= (isEmpty lst) -1) nil) 
   (t (cons (smallList lst 0) (initBoard  (cddddr lst))))))

3 个答案:

答案 0 :(得分:1)

一些评论:

  • someListlstcnt不是惯用的,请使用some-listlistcount
  • 您不需要is-empty,只需使用endpnull,即返回布尔值(不是-1或1)。你可以根据需要制作别名(但为什么?):

    (setf (symbol-function 'is-empty) #'endp)
    

您可以使用small-list的循环:

(defun small-list (list)
  (values (loop repeat 4 collect (pop list)) list))

次要值是列表的其余部分,因此您不需要cddddr

但实际上,在单个函数中初始化整个板可能更好:

(defun init-board (list)
  (loop repeat 4 collect
       (loop repeat 4 collect (pop list))))

第一个LOOP收集4个元素的列表,这些元素由内部LOOP收集。收集的元素将从输入列表中弹出。 现在,如果我想要非常小心,我会添加一些检查并报告错误输入的错误:

(defun init-board (list)
  (flet ((failure ()
           (error "Input list should contain exactly 16 integers: ~S"
                  list)))
    (loop
       with current = list
       repeat 4 collect
         (loop
            repeat 4
            collect (if current
                        (let ((element (pop current)))
                          (check-type element integer)
                          element)
                        (failure)))
       into board
       finally (if list (failure) (return board)))))

另外,我会使用多维数组板。

(make-array '(4 4) :initial-contents (init-board list)) 

答案 1 :(得分:0)

我刚测试了你的三个功能,它给了我正确的输出,所以也许你的问题不在你想象的地方。

(initBoard '(4 5 15 10 14 11 1 8 9 16 6 3 7 2 12 13))

=> ((4 5 15 10) (14 11 1 8) (9 16 6 3) (7 2 12 13))

答案 2 :(得分:0)

我会使用以下递归函数:

(defun smalllist (l n) 
   (when l 
      (cons (subseq l 0 (min n (length l))) 
            (smalllist (nthcdr n l) n))))