Lisp Mapcar就位:以破坏性方式修改列表列表
我有一个列表:setq xs list list 1 2 3 list 4 5 6 list 7 8 9。我想从每个列表中删除第一个元素以获得2 3 5 6 8 9。它很容易做到非破坏性:mapcar的CDRXS。但我想改变原来的清单。我试过:Lisp Mapcar就位:以破坏性方式修改列表列表,lisp,common-lisp,in-place,Lisp,Common Lisp,In Place,我有一个列表:setq xs list list 1 2 3 list 4 5 6 list 7 8 9。我想从每个列表中删除第一个元素以获得2 3 5 6 8 9。它很容易做到非破坏性:mapcar的CDRXS。但我想改变原来的清单。我试过: (mapcar (lambda (x) (setf x (cdr x))) xs) (mapcar (lambda (x) (pop x)) xs) 但它不起作用。如何在不创建任何临时列表的情况下,尽可能有效地更改xs变量的每个列表?使用MAP-INT
(mapcar (lambda (x) (setf x (cdr x))) xs)
(mapcar (lambda (x) (pop x)) xs)
但它不起作用。如何在不创建任何临时列表的情况下,尽可能有效地更改xs变量的每个列表?使用MAP-INTO:
的答案是正确的,请使用。该链接给出了使用宏的示例实现。如果您想从头开始实现映射到,或者使用Emacs Lisp,也可以使用。在Emacs中,Lisp dotimes是在subr.el中实现的,并且不需要。这是映射为1的序列,以映射为结果序列:
(defun map-into (r f xs)
(dotimes (i (min (length r) (length xs)) r)
(setf (elt r i)
(funcall f (elt xs i)))))
对于序列数量可变的版本,我们必须在代码中添加apply和mapcar:
然而,我们看到,elt-inside-dotimes使我们的算法在On2中工作。我们可以通过使用“谢谢”对其进行优化
在mapcar中不起作用的原因是setf是一个扩展为表达式的函数,可以操作它所变异的数据。在mapcar内部的lambda作用域中,它只能访问该lambda的局部变量,而不能访问传递给mapcar本身的序列,因此它如何知道将修改后的值放回何处?这就是为什么问题中的mapcar代码返回修改过的列表列表,但不会对其进行适当的修改。只需尝试宏扩展“setf elt xs 0 funcall”cdr elt xs 0,然后自己查看。使用elt访问列表中的元素(如此)代价高昂。它使函数在n2时间而不是n时间内运行。最好跟踪列表的尾部,以便始终获得第一个元素。你可以用它来有效地完成这项工作。例如,要从每个列表中删除第一个元素,可以映射lambda tail pop first tail list。请参阅编辑。这些新功能是否适用于?另外,是否可以将变量参数映射简化为?新函数已启用,这很好。不过,我认为您可以将map的第二个实现简化为。例如,见。
(defun map-into (r f xs)
(dotimes (i (min (length r) (length xs)) r)
(setf (elt r i)
(funcall f (elt xs i)))))
(defun map-into (r f &rest xss)
(dotimes (i (apply 'min (length r) (mapcar 'length xss)) r)
(setf (elt r i)
(apply f (mapcar (lambda (s) (elt s i))
xss)))))
(defun map-into (rs f xs)
(mapl (lambda (r x) (setf (car r) (funcall f (car x)))) rs xs))
(defun map-into (rs f &rest xss)
(mapl (lambda (r xs)
(setf (car r)
(apply f (car xs))))
rs
(apply 'mapcar 'list xss))) ;; transpose a list of lists