【问题标题】:Adding two alists by values in elisp在elisp中按值添加两个alist
【发布时间】:2012-04-08 06:57:15
【问题描述】:

我有两个点对形式的列表:

(((key1 . value1) . 5)
 ((key2 . value2) . 7))

(((key2 . value2) . 3)
 ((key3 . value3) . 9))

我希望结果是一个关联列表:

(((key1 . value1) . 5)
 ((key2 . value2) . 10)
 ((key3 . value3) . 9))

如何在 emacs lisp 中按值添加两个关联列表?换句话说,如果两个 alist 具有相同的键,则该键的值应相加得到结果 alist。

对此最可能的答案是一些 elisp sn-p,但我也更喜欢漂亮的 emacs 宏。

【问题讨论】:

    标签: emacs lisp elisp associative-array


    【解决方案1】:

    使用 CL 模块的解决方案(编写时考虑到可读性而不是效率):

    (require 'cl)
    
    (defun merge-alists (function default alist1 alist2)
      (flet ((keys (alist) (mapcar #'car alist))
             (lookup (key alist) (or (cdr (assoc key alist)) default)))
        (loop with keys = (union (keys alist1) (keys alist2) :test 'equal)
              for k in keys collect
              (cons k (funcall function (lookup k alist1) (lookup k alist2))))))
    

    你可以这样使用它:

    elisp> (merge-alists '+ 0 '((foo . 1) (bar . 2)) '((foo . 11) (baz . 22)))
    ((baz . 22)
     (foo . 12)
     (bar . 2))
    
    elisp> (merge-alists '* 1 '((foo . 1) (bar . 2)) '((foo . 11) (baz . 22)))
    ((baz . 22)
     (foo . 11)
     (bar . 2))
    
    elisp> (merge-alists 'append '() '((foo a b) (bar c)) '((foo d e) (baz f g)))
    ((baz f g)
     (foo a b d e)
     (bar c))
    
    elisp> (setq my-alist1 '(((key1 . value1) . 5) ((key2 . value2) . 7)))
    (((key1 . value1) . 5)
     ((key2 . value2) . 7))
    
    elisp> (setq my-alist2 '(((key2 . value2) . 3) ((key3 . value3) . 9)))
    (((key2 . value2) . 3)
     ((key3 . value3) . 9))
    
    elisp> (merge-alists '+ 0 my-alist1 my-alist2)
    (((key3 . value3) . 9)
     ((key1 . value1) . 5)
     ((key2 . value2) . 10))
    

    【讨论】:

      【解决方案2】:

      可能是这样的:

      (defun merge-alists (a1 a2)
         (let ((ac (copy-alist a1)))
            (dolist (x a2)
               (when (null (assoc (car x) ac))
              (add-to-list 'ac x)))
            ac))
      

      它将返回第一个列表的副本,其中包含从第二个列表添加的数据...

      但是,如果您使用简单的append 函数,那么无论如何都不会找到重复项,因为函数通常会返回第一个找到的值,而不是所有存在的值。

      更新:对不起,错误地阅读了问题,另一个答案正确,并且以更一般的方式......虽然,这是我的这个函数的变体,没有使用 CL 包:

      (defun merge-alists (a1 a2)
        (let ((ac (copy-alist a1)))
          (dolist (x a2)
            (let ((r (assoc (car x) ac)))
          (if (null r)
            (add-to-list 'ac x)
            (setf (cdr r) (+ (cdr x) (cdr r))))))
          ac))
      

      附:在您的示例中,括号是不平衡的:-)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多