2012-04-08 3 views
2

Ich habe zwei Listen von punktierten Paaren der Form:Hinzufügen von zwei Alists von Werten in elisp

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

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

Ich mag das Ergebnis eine Zuordnungsliste sein:

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

Wie ich hinzufügen zwei Assoziationslisten nach Werten in Emacs Lisp? Mit anderen Worten, wenn zwei Alists den gleichen Schlüssel haben, sollten die Werte für diesen Schlüssel in dem sich ergebenden Alis zusammenaddiert werden.

Die wahrscheinlichste Antwort dafür ist, einige elisp Schnipsel, aber ich würde auch eine nette Emacs Makro bevorzugen.

Antwort

3

Eine Lösung des CL-Modul (geschrieben mit Ablesbarkeit anstatt Effizienz im Vordergrund) mit:

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

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

Sie es wie folgt verwenden können

2

Es könnte so etwas wie:

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

es wird mit Daten Kopie ersten Liste zurück aus der zweiten Liste hinzugefügt ...

Aber wenn Sie einfach append Funktion verwenden werden, dann Duplikate gewonnen Sie werden sowieso nicht gefunden, da Funktionen normalerweise den ersten gefundenen Wert zurückgeben, nicht alle, die existieren.

Update: sorry, falsch gelesen Frage, eine andere Antworten, die es tun, richtig, und in allgemeiner Art und Weise ... Obwohl, hier meine Variante dieser Funktion ist, ohne CL-Paket mit:

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

P. S. in Ihrem Beispiel sind Klammern unausgewogen :-)

Verwandte Themen