【问题标题】:Mapping a function over two lists in elisp在elisp中的两个列表上映射一个函数
【发布时间】:2012-02-20 04:05:57
【问题描述】:

在普通的 lisp 中我可以这样做:

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

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

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

(wrong-number-of-arguments mapcar 3)

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

【问题讨论】:

    标签: lisp elisp


    【解决方案1】:

    您需要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)))))
    

    【讨论】:

    • 因为它是 cl-macs 的一部分,所以你应该把它称为 cl-mapcar 并确保 (require 'cl-lib)
    【解决方案2】:

    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-withcl-mapcar 相同应用于2 个列表):

    (-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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-13
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多