在常见的lisp中,我可以这样做:
(mapcar #'cons '(1 2 3) '(a b c))
=> ((1 . A) (2 . B) (3 . C))
我如何在elisp中做同样的事情?当我尝试时,我收到一个错误:
(wrong-number-of-arguments mapcar 3)
如果elisp的mapcar一次只能在一个列表上工作,那么将两个列表组合成一个列表的个人方法是什么?
答案 0 :(得分:17)
你想要mapcar*
,它接受一个或多个序列(不仅仅是Common Lisp中的列表),而一个序列参数就像常规mapcar
一样工作。
(mapcar* #'cons '(1 2 3) '(a b c))
((1 . A) (2 . B) (3 . C))
即使没有定义,你也可以轻松自己动手:
(defun mapcar* (f &rest xs)
"MAPCAR for multiple sequences"
(if (not (memq nil xs))
(cons (apply f (mapcar 'car xs))
(apply 'mapcar* f (mapcar 'cdr xs)))))
答案 1 :(得分:9)
Emacs内置Common Lisp library,它引入了大量Common Lisp函数和宏,但带有cl-
前缀。没有理由避免使用此库。 cl-mapcar
就是你想要的:
(cl-mapcar '+ '(1 2 3) '(10 20 30)) ; (11 22 33)
使用dash
列表操作库(请参阅installation instructions),您可以使用-zip-with
(请记住:-zip-with
与应用于cl-mapcar
的{{1}}相同列表):
(-zip-with '+ '(1 2 3) '(10 20 30)) ; (11 22 33)
我不知道为3个参数实现-zip-with
等价的优雅方法。但是,您可以使用 dash-functional
包中的-partial
,其中包含 dash
(来自 dash-functional
的功能需要Emacs 24)。 -partial
部分应用了该函数,因此下面的这两个函数调用是等效的:
(-zip-with '+ '(1 2) '(10 20)) ; (11 22)
(funcall (-partial '-zip-with '+) '(1 2) '(10 20)) ; (11 22)
然后,您可以将其与-reduce
函数一起使用:
(-reduce (-partial '-zip-with '+) '((1 2 3) (10 20 30) (100 200 300)))
; (111 222 333)
您可以将其包装到具有&rest
关键字的函数中,因此此函数将接受不同数量的参数而不是列表:
(defun -map* (&rest lists)
(-reduce (-partial 'zip-with '+) lists))