在lisp中转置列表列表的安全方法?

Mic*_*Fox 1 common-lisp

转换列表很容易,但需要注意的是,不能超过call-arguments-limit.

http://www.lispworks.com/kb/4fbc798cb17237ca852566da005fcc79.html

当列表长度超过时,什么是一种安全的写入转置方式call-arguments-limit

例如,答案不是这个:https://stackoverflow.com/a/3513158/914859

(defun transpose (list-of-lists)
  (apply #'mapcar #'list list-of-lists))
Run Code Online (Sandbox Code Playgroud)

sds*_*sds 5

这是一个不受其他call-arguments-limit人约束的非递归版本:

(defun pop-all (list-of-lists)
  "Pop each list in the list, return list of pop results
and an indicator if some list has been exhausted."
  (loop for tail on list-of-lists collect (pop (car tail))))

(defun transpose (list-of-lists)
  "Transpose the matrix."
  (loop with tails = (copy-list list-of-lists)
    while (some #'consp tails) ; or any?
    collect (pop-all tails)))
Run Code Online (Sandbox Code Playgroud)

测试:

(defparameter ll '((1 4 7) (2 5 8) (3 6 9)))
(transpose ll)
==> ((1 2 3) (4 5 6) (7 8 9))
ll
==> ((1 4 7) (2 5 8) (3 6 9))
(equal ll (transpose (transpose ll)))
==> T
Run Code Online (Sandbox Code Playgroud)

请注意,我每次迭代扫描list-of-lists 两次 - 一次进入some和进入一次pop-all(与类似的答案相同).

我们可以通过一些额外的工作来避免它:

(defun pop-all (list-of-lists)
  "Pop each list in the list, return list of pop results
and an indicator if some list has been exhausted."
  (loop for tail on list-of-lists
    for more = (consp (car tail)) then (and more (consp (car tail)))
    collect (pop (car tail)) into card
    finally (return (values cars more))))

(defun transpose (list-of-lists)
  "Transpose the matrix."
  (loop with tails = (copy-list list-of-lists) and more and cars
    do (setf (values cars more) (pop-all tails))
    while more collect cars))
Run Code Online (Sandbox Code Playgroud)