在Common Lisp中转置列表

时间:2010-08-18 14:27:04

标签: lisp common-lisp

我试图转置列表清单;我的评论表明了思考过程。

(setq thingie  '((1 2 3) (4 5 6) (7 8 9)))  ;;test case

(defun trans (mat)
  (if (car mat)
    (let ((top (mapcar 'car  mat))   ;;slice the first row off as a list
          (bottom (mapcar 'cdr mat))) ;;take the rest of the rows
      (cons top (trans bottom))))    ;;cons the first-row-list with the next-row-list
   mat)

(trans thingie)
=> ((1 2 3) (4 5 6) (7 8 9))           ;;wait what? 

但是,我真的希望它是

((1 4 7) (2 5 8) (3 6 9))

我做错了什么?

1 个答案:

答案 0 :(得分:25)

有一种简单的方法:

(defun rotate (list-of-lists)
  (apply #'mapcar #'list list-of-lists))

您的尝试始终返回原始mat。修复缩进,您会发现if表单中返回的值总是被丢弃。

编辑:如何运作:

  • List接受任意数量的参数并列出它。它的功能定义可以这样设想:

    (defun list (&rest arguments)
      arguments) ; exploit the automatic &rest construction
    
  • Mapcar获取一个函数和任意数量的列表,然后创建一个 通过调用函数创建的值的新列表 这些清单中的一个要素。示例:(mapcar #'foo '((A B) (C D)))将构造一个新列表,其中第一个元素是 结果为(foo 'A 'C),第二个结果为(foo 'B 'D)

  • Apply将可扩展参数列表指示符作为最后一个 论点。这意味着如果你给它一个列表作为它的最后一个 参数,该列表可以“传播”以产生单个参数 为功能。示例:(apply #'+ '(1 2 3))具有相同的功能 效果为(+ 1 2 3)

现在你可以扩展这一行:

(apply #'mapcar #'list '((A B) (C D)))

=>

(mapcar #'list '(A B) '(C D))

=>

(list (list 'A 'C) (list 'B 'D))

=>

'((A C) (B D))