2

I have two lists of dotted-pairs of the form:

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

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

i want the result to be an association list:

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

How do i add two association lists by values in emacs lisp? In other words, if two alists have the same key, then values for that key should be added together in resulting alist.

The most probable answer for this is some elisp snippet, but i would also prefer a nifty emacs macro.

4

2 に答える 2

3

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))
于 2012-04-08T10:50:43.013 に答える
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))

2番目のリストから追加されたデータを含む最初のリストのコピーを返します。

ただし、単純な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))

あなたの例のPSでは、括弧は不均衡です:-)

于 2012-04-08T08:36:05.173 に答える