İki özellik listesini birleştirme işlevi?


11

Bunun gibi iki özellik listesini birleştirmek için standart Elisp kütüphane işlevi bulamadık:

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

Bununla bir şeyler inşa edebilirim dolist, ama yapmadan önce, bazı kütüphanelerde var olan bir işleve bakmadığımı kontrol etmek istiyorum.

Yorumlara dayalı güncellemeler :

  1. "Çok yönlü" yoruma yanıt olarak:

Ben soruya farklı (ve muhtemelen geçerli) cevaplar var çünkü böyle bir işlev olmadığını hayal ediyorum: farklı değerlerle yinelenen özellik adları olduğunda ne yapmalı?

Evet, kopyaları nasıl birleştireceğinizle ilgili bir soru var, ancak bunu ele almanın nispeten az yolu var. İki genel yaklaşım görüyorum. İlk olarak, argüman sırası kopyaları çözebilir; Clojure'un birleşmesinde olduğu gibi en sağda kazanır . İkincisi, birleştirme, Ruby'nin birleştirmesinde olduğu gibi, kullanıcı tarafından sağlanan geri arama işlevine devredilebilir .

Her durumda, bunu yapmanın farklı yolları olması, diğer birçok dil standart kütüphanesinin bir birleştirme işlevi sağlamasını engellemez. Aynı genel argüman sıralamada da söylenebilir, ancak Elisp sıralama işlevi sunar.

  1. "Detaylandırabilir misin?" / "Lütfen tam olarak aradığınız davranışı belirtin."

Genel olarak konuşmak gerekirse, Elisp topluluğunun kullandığı şeylere açıkım. Belirli bir örnek istiyorsanız, işinize yarayacak bir örnek aşağıdadır:

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

Ve geri dönüyor

'(k1 1 k2 2 k3 0))

Bu, Clojure'un birleşmesi gibi, en çok kazanılan bir stil olacaktır.

  1. "Bunlar listeler, yani eklensin mi?"

Hayır, özellik listesi semantiğini appendkorumaz . Bu:

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

Bunu döndürür:

(k1 1 k2 2 k2 0)

append, C kaynak kodunda yerleşik bir fonksiyondur.

(SEQUENCES ekleyin ve dinlenin)

Tüm argümanları birleştirin ve sonucu bir liste yapın. Sonuç, öğeleri tüm bağımsız değişkenlerin öğeleri olan bir listedir. Her argüman bir liste, vektör veya dize olabilir. Son argüman kopyalanmaz, sadece yeni listenin kuyruğu olarak kullanılır.

  1. "Ve örneğin birleştirme gibi bir şey göstermiyor - iki özellik listesi bile göstermiyor."

Evet öyle; birleştirmeyi adım adım yapar. Elisp'in belgelenmiş özellik listesi işlevlerini kullanarak birleştirme yapmanın acı verici bir şekilde nasıl ayrıntılı olduğunu gösterir:

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

Ortaya çıkan çıktı değerini aşağıdakilerden görüntülemeniz yeterlidir pl:

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

Tekrarlamak gerekirse, bu sorunu çözmek için bir işlev yazabiliyorum, ama önce böyle bir işlevin ortak kullanımda bir yerde olup olmadığını anlamak istedim.

Son olarak, soruyu belirsiz bulduğunuz için aşağı düşürdüyseniz, açıklığa kavuşturmak için biraz çaba harcadığımı şimdi tekrar düşünmenizi rica ediyorum. Bu araştırma eksikliği değil. "Listeler" deki Elisp dokümanları soruya cevap vermiyor.


2
Bunlar listeler, yani append?
abo-abo

2
Lütfen aradığınız davranışı tam olarak belirtin. İki listeyi "birleştirmenin" birçok yolu vardır. Örneğin, birleştirme gibi bir şey göstermez - iki özellik listesi bile göstermez. Şimdiye kadar, bu soru belirsiz olarak kapatılmalıdır. FWIW, bir plistin önüne daha yakın bir çiftin, önden daha uzak olan aynı tuşa sahip herhangi bir çifti gölgelediğini unutmayın. Bu yüzden birleştirme, bir plistten elementleri diğerinden elementlerin önüne koymak anlamına gelebilir.
Drew

1
@ Abo-Abo: O çıkıyor Manuel Emacs Lisp açıkça belirtmektedir özellik adları farklı olmalıdır .
Konstantin

3
En sağdaki listeyi kazanmak için sadece geçtiğiniz listelerin sırasını tersine çevirmeniz yeterlidir append: (let ((args '((:a 1 :b 1) (:b 2) (:a 3)))) (apply #'append (reverse args))) => (:a 3 :b 2 :a 1 :b 1)bu (:a 3 :b 2 :a 1)sadece pliste erişmek için plist işlevlerini kullandığınız sürece aynıdır .
tarsius

1
@Constantine: sağ, ne olsa plist-getne plist-memberbirden fazla özdeş tuşları varsa umurumda. Onlar bu konuda alists benzer şekilde davranırlar anlaşılıyor: (plist-get '(:a "a" :b "b" :a "c") :a) ==> "a". Bu arada, (plist-put '(:a "a" :b "b" :a "c") :a "d")birinci :aanahtarın değerini değiştirir ancak ikincisinin değerini değiştirmez .
Dan

Yanıtlar:


8

Emacs'ın içerdiği kuruluş kipinin plist birleştirme işlevi vardır:

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

Kullanmak için (require 'org)önce dosyayı yüklemeniz gerekir . Ne yazık ki, çok büyük bir dosya, 900 + KB, bu yüzden bir yardımcı program kütüphanesi olarak gerçekten kullanılamaz. Standart bir plist paketi gibi bir şey olması güzel olurdu.

Yakın zamanda çok küçük bir tanesine başladım ve alistlerin ve plistlerin aynı şekilde argüman olarak ele alınmadığını fark ettim - örneğin (plist-get LIST KEY) vs (assoc KEY LIST), ki bu optimizasyonun talihsiz bir kalıntısı olmalı (veya?) .

Ancak, evet, Emacs'ın güzel bir plist kütüphanesine ihtiyacı var - Aramamda biriyle karşılaşmadım, ancak orada bir yerlerde bir tane olması hala mümkün, yoksa başka bir tane başlatmak ve Elpa / Melpa'ya koymak zorundayız .

Aynı arayüze sahip bir alist kütüphanesi de güzel olurdu.


6

Kılavuzu okumak ve listeye göz atmak, C-u C-h a plist RETiki özellik listesini birleştirmek için herhangi bir işlevi açmaz. Ortak Lisp uzantıları özellikle özellik listelerinde işlem yapmak için herhangi bir işlev sağlamaz, yalnızca yer ( getf/ setf/…) desteği sağlar. Yani ya bir üçüncü taraf kütüphanesine güvenmeniz ya da kendi kütüphanenizi yuvarlamanız gerekir.

Kendinizi yuvarlamak çok zor değil. Bu uygulama, çakışma durumunda son değeri kullanır.

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

Güzel. Neden copy-sequenceilk plistsiniz ama diğerleri değilsiniz? Ayrıca, yuvalamayı cadrve ile biraz temizleyebilirsiniz cddr.
fommil

aslında, org-combine-plists(aşağıda) az çok temizlenmiş versiyonudur. Hala neden copy-sequencearaba olduklarını anlamıyorum .
fommil

0

Bunun zaten cevaplandığını biliyorum, ama herkes ilgilenirse, orguygulamayı aldım ve üzerinde biraz kod golf oynadım

(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))))))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.