2つのプロパティリストをマージする関数?


11

次のように、2つのプロパティリストをマージする標準のElispライブラリ関数が見つかりません。

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

で何かを構築できますがdolist、その前に、ライブラリの既存の関数を見落としていないことを確認したいと思います。

コメントに基づく更新

  1. 「多方向」コメントへの応答:

私はそのような関数は存在しないと想像します。異なる(そして有効な)可能性のある質問に対する回答が存在するためです。異なる値を持つ重複したプロパティ名がある場合はどうすればよいですか?

はい、重複をマージする方法についての質問がありますが、それに対処する方法は比較的少数です。一般的なアプローチは2つあります。まず、引数の順序で重複を解決できます。たとえば、Clojureのマージのように、右端の勝利。第2に、Rubyのmergeの場合と同様に、マージはユーザー指定のコールバック関数に委任できます。

いずれにせよ、さまざまな方法があるという事実は、他の多くの言語標準ライブラリがマージ機能を提供することを妨げません。同じ一般的な議論はソートについても言えますが、Elispはソート機能を提供します。

  1. 「詳しく説明していただけませんか?」/「探している動作を正確に指定してください。」

一般的に言って、私はElispコミュニティーが使用するものにオープンです。特定の例が必要な場合は、次の例が機能します。

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

そして戻る

'(k1 1 k2 2 k3 0))

これは、Clojureのマージのように、最も右勝者のスタイルになります。

  1. 「それらはリストなので、追加するだけですか?」

いいえ、プロパティリストのセマンティクスappendは保持されません。この:

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

これを返します:

(k1 1 k2 2 k2 0)

appendは、「Cソースコード」の組み込み関数です。

(シーケンスに残りを追加)

すべての引数を連結し、結果をリストにします。結果は、要素がすべての引数の要素であるリストです。各引数は、リスト、ベクトル、または文字列です。最後の引数はコピーされず、新しいリストの末尾として使用されます。

  1. 「そしてあなたの例はマージのようなものを何も示していません-それは2つのプロパティリストさえ示していません。」

はい、そうです; マージは段階的に行われます。Elispのドキュメント化されたプロパティリスト関数を使用してマージを行うと、非常に冗長になることを示しています。

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

の結果の出力値を表示するだけですpl

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

繰り返しになりますが、私はこの問題を解決する関数を書くことができますが、最初に、そのような関数が一般的に使用されている場所に存在するかどうかを知りたいと思いました。

最後に、不明な点があるために質問に反対票を投じた場合は、私が明確にするためにいくらかの努力を払ったことを今再考するようにお願いします。これは研究の不足ではありません。「リスト」に関するElispのドキュメントは質問に答えません。


2
彼らはリストなので、ただappend
abo-abo 2014

2
探している動作を正確に指定してください。2つのリストを「マージ」するには多くの方法があります。そして、あなたの例はマージのようなものを何も示していません-それは2つのプロパティリストさえ示していません。これまでのところ、この質問は不明確であるとして閉じられるべきです。FWIW、plistの前面に近いペアは、前面から離れた同じキーを持つペアをシャドウすることに注意してください。マージはなど、他の要素の前に1つのplistからの要素を置くことを意味することができるように
ドリュー

1
@ abo-abo:Emacs Lispマニュアルでは、プロパティ名は明確に区別する必要があると明記されています
コンスタンティン

3
右端のリストを獲得するには、渡すリストの順序を逆にするだけですappend(let ((args '((:a 1 :b 1) (:b 2) (:a 3)))) (apply #'append (reverse args))) => (:a 3 :b 2 :a 1 :b 1)これは、(:a 3 :b 2 :a 1)plist関数を使用してplistにアクセスするだけの場合と同じです。
tarsius 2014

1
@Constantine:そうですが、同一のキーが複数あるかどうかplist-getplist-member気にしません。この点で、それらは連想リストと同様に動作するように見えます(plist-get '(:a "a" :b "b" :a "c") :a) ==> "a"。一方、(plist-put '(:a "a" :b "b" :a "c") :a "d")最初の:aキーの値を置き換えますが、2番目のキーは置き換えません。
ダン

回答:


8

Emacsに含まれているOrg-modeには、plistマージ機能があります。

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

それを使用するには、(require 'org)最初にファイルをロードする必要があります。残念ながら、これは900 + KBの非常に大きなファイルであるため、ユーティリティライブラリとしては実際には使用できません。標準のplistパッケージのようなものがあればいいでしょう。

私は最近非常に小さなものを始め、alistsとplistsが引数のように同じように扱われていないことに気づきました-例(plist-get LIST KEY)と(assoc KEY LIST)は、残念ながら最適化の遺物(または?) 。

しかし、はい、Emacsには素晴らしいplistライブラリが必要です-私は検索で1つも見つけませんでしたが、どこかにそれがまだ存在する可能性があります。そうでない場合、1つを開始してElpa / Melpaに配置する必要があります。

同じインターフェースを持つ連想ライブラリーもあるとよいでしょう。


6

マニュアルを読んでリストを閲覧しても、C-u C-h a plist RET2つのプロパティリストをマージする機能はありません。Common Lisp拡張機能は、プロパティリストを操作するための機能を提供せず、配置(getf/ setf/…)サポートのみを提供します。したがって、サードパーティのライブラリに依存するか、独自のライブラリを作成する必要があります。

自分で転がすことはそれほど難しくありません。この実装では、競合が発生した場合に最後の値を使用します。

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

いいね。なぜあなたcopy-sequenceは最初のリストではなく他のリストですか?そしてまた、あなたが営巣Aビットをクリーンアップすることができますcadrcddr
fommil

実際、org-combine-plists(下)は多かれ少なかれクリーンアップされたバージョンです。なぜ彼らcopy-sequenceが車なのかまだわかりません。
fommil

0

私はこれがすでに回答されていることを知っていますが、誰かが興味がある場合は、org実装を取り、コードゴルフを少しプレイしました

(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))))))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.