代码之家  ›  专栏  ›  技术社区  ›  Paul Nathan

通用Lisp中的转置列表

  •  11
  • Paul Nathan  · 技术社区  · 14 年前

    我试图改变一个列表;我的评论指出了思考的过程。

    (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 回复  |  直到 11 年前
        1
  •  25
  •   Svante    14 年前

    有一个简单的方法:

    (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 获取一个函数和任意数量的列表,然后 通过调用函数always with创建的新值列表 这些列表中的一个元素。例子: (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)))
    

    = & gt;

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

    = & gt;

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

    = & gt;

    '((A C) (B D))