Funktion zum Zusammenführen von zwei Eigenschaftslisten?


11

Ich habe keine Standardfunktion für die Elisp-Bibliothek gefunden, mit der zwei Eigenschaftslisten wie folgt zusammengeführt werden können:

(setq pl nil)
(setq pl (plist-put pl 'key-1 'value-1))
(setq pl (plist-put pl 'key-2 'value-2))

Ich könnte etwas damit bauen dolist, aber bevor ich es tue, möchte ich überprüfen, ob ich eine vorhandene Funktion in einer Bibliothek nicht übersehen kann.

Updates, basierend auf den Kommentaren :

  1. Als Antwort auf den Kommentar "Vielseitigkeit":

Ich würde mir vorstellen, dass es eine solche Funktion nicht gibt, weil es unterschiedliche (und möglicherweise gültige) Antworten auf die Frage gibt: Was tun, wenn Sie doppelte Eigenschaftsnamen mit unterschiedlichen Werten haben?

Ja, es gibt eine Frage zum Zusammenführen von Duplikaten, aber es gibt relativ wenige Möglichkeiten, dies zu beheben. Ich sehe zwei allgemeine Ansätze. Erstens könnte die Argumentreihenfolge die Duplikate auflösen. zB gewinnt ganz rechts, wie bei Clojures Fusion . Zweitens könnte die Zusammenführung an eine vom Benutzer bereitgestellte Rückruffunktion delegieren, wie bei Rubys Zusammenführung .

In jedem Fall hindert die Tatsache, dass es verschiedene Möglichkeiten gibt, dies zu tun, viele andere Sprachstandardbibliotheken nicht daran, eine Zusammenführungsfunktion bereitzustellen. Das gleiche allgemeine Argument könnte für das Sortieren gelten, und dennoch bietet Elisp Sortierfunktionen.

  1. "Könnten Sie näher darauf eingehen?" / "Bitte geben Sie das gesuchte Verhalten genau an."

Generell bin ich offen für das, was die Elisp-Community nutzt. Wenn Sie ein bestimmtes Beispiel wünschen, wäre hier ein Beispiel, das funktionieren würde:

(a-merge-function '(k1 1) '(k2 2 k3 3) '(k3 0))

Und kehrt zurück

'(k1 1 k2 2 k3 0))

Dies wäre ein Stil, der ganz rechts gewinnt, wie die Fusion von Clojure.

  1. "Das sind Listen, also einfach anhängen?"

Nein, appenddie Semantik der Eigenschaftsliste wird nicht beibehalten . Dies:

(append '(k1 1 k2 2) '(k2 0))

Gibt Folgendes zurück:

(k1 1 k2 2 k2 0)

append ist eine integrierte Funktion im C-Quellcode.

(Anhängen und Ausruhen SEQUENZEN)

Verketten Sie alle Argumente und machen Sie das Ergebnis zu einer Liste. Das Ergebnis ist eine Liste, deren Elemente die Elemente aller Argumente sind. Jedes Argument kann eine Liste, ein Vektor oder eine Zeichenfolge sein. Das letzte Argument wird nicht kopiert, sondern nur als Ende der neuen Liste verwendet.

  1. "Und Ihr Beispiel zeigt nichts wie eine Zusammenführung - es zeigt nicht einmal zwei Eigenschaftslisten."

Ja tut es; Die Zusammenführung erfolgt Schritt für Schritt. Es zeigt, wie schmerzhaft das Zusammenführen mit den dokumentierten Eigenschaftenlistenfunktionen von Elisp ist:

(setq pl nil)
(setq pl (plist-put pl 'key-1 'value-1))
(setq pl (plist-put pl 'key-2 'value-2))

Zeigen Sie einfach den resultierenden Ausgabewert an von pl:

(key-1 value-1 key-2 value-2)

Um es noch einmal zu wiederholen, ich bin in der Lage, eine Funktion zu schreiben, um dieses Problem zu lösen, aber ich wollte zuerst herausfinden, ob eine solche Funktion irgendwo allgemein gebräuchlich ist.

Wenn Sie die Frage abgelehnt haben, weil Sie sie unklar fanden, würde ich Sie bitten, sie jetzt zu überdenken, da ich mich bemüht habe, sie zu klären. Dies ist kein Mangel an Forschung. Die Elisp-Dokumentation zu "Listen" beantwortet die Frage nicht.


2
Das sind Listen, also nur append?
Abo-Abo

2
Bitte geben Sie das gewünschte Verhalten genau an. Es gibt viele Möglichkeiten, zwei Listen "zusammenzuführen". Und Ihr Beispiel zeigt nichts wie eine Zusammenführung - es zeigt nicht einmal zwei Eigenschaftslisten. Bisher sollte diese Frage als unklar abgeschlossen werden. FWIW, beachten Sie, dass ein Paar, das näher an der Vorderseite einer Liste liegt, jedes Paar mit demselben Schlüssel beschattet, der weiter von der Vorderseite entfernt ist. Zusammenführen kann also bedeuten, Elemente von einer Liste vor Elemente von der anderen zu setzen usw.
Drew

1
@ abo-abo: Es stellt sich heraus, dass im Emacs Lisp-Handbuch ausdrücklich angegeben ist, dass Eigenschaftsnamen unterschiedlich sein müssen .
Konstantin

3
Um die Liste ganz rechts zu gewinnen, müssen Sie nur die Reihenfolge der Listen umkehren, an die Sie übergeben append: (let ((args '((:a 1 :b 1) (:b 2) (:a 3)))) (apply #'append (reverse args))) => (:a 3 :b 2 :a 1 :b 1)Dies ist dieselbe, (:a 3 :b 2 :a 1)solange Sie nur Plist-Funktionen verwenden, um auf die Plist zuzugreifen.
Tarsius

1
@Constantine: Richtig, obwohl es weder plist-getnoch wichtig zu sein plist-memberscheint, ob es mehrere identische Schlüssel gibt. Es sieht so aus, als würden sie sich in dieser Hinsicht analog zu Alisten verhalten : (plist-get '(:a "a" :b "b" :a "c") :a) ==> "a". (plist-put '(:a "a" :b "b" :a "c") :a "d")Ersetzt in der Zwischenzeit den Wert des ersten :aSchlüssels, nicht jedoch des zweiten.
Dan

Antworten:


8

Der in Emacs enthaltene Org-Modus verfügt über eine Plist-Merge-Funktion:

(defun org-combine-plists (&rest plists)
  "Create a single property list from all plists in PLISTS.
The process starts by copying the first list, and then setting properties
from the other lists.  Settings in the last list are the most significant
ones and overrule settings in the other lists."
  (let ((rtn (copy-sequence (pop plists)))
        p v ls)
    (while plists
      (setq ls (pop plists))
      (while ls
        (setq p (pop ls) v (pop ls))
        (setq rtn (plist-put rtn p v))))
    rtn))

Um es zu verwenden, müssen Sie (require 'org)zuerst die Datei laden. Leider handelt es sich um eine sehr große Datei mit mehr als 900 KB, sodass sie nicht wirklich als Dienstprogrammbibliothek verwendet werden kann. So etwas wie ein Standard-Plist-Paket wäre schön zu haben.

Ich habe kürzlich eine sehr kleine angefangen und festgestellt, dass Alisten und Plisten nicht gleich behandelt werden, z. B. (plist-get LIST KEY) vs (assoc KEY LIST), was ein unglückliches Relikt der Optimierung sein muss (oder?) .

Aber ja, Emacs braucht eine nette Plist-Bibliothek - ich bin bei meiner Suche nicht auf eine gestoßen, aber es ist immer noch möglich, dass es irgendwo eine gibt, oder wir müssen eine starten und sie auf Elpa / Melpa setzen .

Eine Alist-Bibliothek mit der gleichen Oberfläche wäre auch schön zu haben.


6

Das Lesen des Handbuchs und das Durchsuchen der Liste von C-u C-h a plist RETzeigt keine Funktion zum Zusammenführen von zwei Eigenschaftslisten an. Die Common Lisp-Erweiterungen bieten keine spezielle Funktion für Eigenschaftslisten, sondern nur Platzunterstützung ( getf/ setf/…). Sie müssen sich also entweder auf eine Bibliothek eines Drittanbieters verlassen oder Ihre eigene rollen.

Das eigene Rollen ist nicht allzu schwierig. Diese Implementierung verwendet im Konfliktfall den letzten Wert.

(defun plist-merge (&rest plists)
  (if plists
      (let ((result (copy-sequence (car plists))))
        (while (setq plists (cdr plists))
          (let ((plist (car plists)))
            (while plist
              (setq result (plist-put result (car plist) (car (cdr plist)))
                    plist (cdr (cdr plist))))))
        result)
    nil))

(plist-merge '(:x 2 :y 3)
             '(     :y 0 :z 7))
=>            (:x 2 :y 0 :z 7)

nett. Warum bist du copy-sequencedie erste Liste, aber nicht die anderen? Außerdem können Sie die Verschachtelung mit cadrund ein wenig aufräumen cddr.
am

Tatsächlich ist org-combine-plists(unten) mehr oder weniger die bereinigte Version. Ich verstehe immer noch nicht, warum sie copy-sequencedas Auto.
am

0

Ich weiß, dass dies bereits beantwortet wurde, aber falls jemand interessiert ist, habe ich die orgImplementierung übernommen und ein bisschen Code Golf darauf gespielt

(defun plist-merge (&rest plists)
  "Create a single property list from all PLISTS.
Inspired by `org-combine-plists'."
  (let ((rtn (pop plists)))
    (dolist (plist plists rtn)
      (setq rtn (plist-put rtn
                           (pop plist)
                           (pop plist))))))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.