将函数映射到elisp中的两个列表

时间:2012-01-27 03:42:06

标签: lisp elisp

在常见的lisp中,我可以这样做:

(mapcar #'cons '(1 2 3) '(a b c))

=> ((1 . A) (2 . B) (3 . C))

我如何在elisp中做同样的事情?当我尝试时,我收到一个错误:

(wrong-number-of-arguments mapcar 3)

如果elisp的mapcar一次只能在一个列表上工作,那么将两个列表组合成一个列表的个人方法是什么?

2 个答案:

答案 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))