Berfungsi untuk menggabungkan dua daftar properti?


11

Saya belum menemukan fungsi perpustakaan Elisp standar untuk menggabungkan dua daftar properti, seperti ini:

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

Saya dapat membangun sesuatu dengan dolist, tetapi sebelum saya melakukannya, saya ingin memeriksa bahwa saya tidak mengabaikan fungsi yang ada di beberapa perpustakaan.

Pembaruan, berdasarkan komentar :

  1. Menanggapi komentar "banyak cara":

Saya akan membayangkan bahwa tidak ada fungsi seperti itu karena ada jawaban yang berbeda (dan mungkin valid) untuk pertanyaan: apa yang harus dilakukan ketika Anda memiliki nama properti duplikat dengan nilai yang berbeda?

Ya, ada pertanyaan tentang cara menggabungkan duplikat, tetapi ada beberapa cara untuk mengatasinya. Saya melihat dua pendekatan umum. Pertama, urutan argumen dapat menyelesaikan duplikat; mis. kemenangan paling kanan, seperti pada gabungan Clojure . Kedua, penggabungan dapat mendelegasikan ke fungsi panggilan balik yang disediakan pengguna, seperti dalam gabungan Ruby .

Bagaimanapun, fakta bahwa ada berbagai cara untuk melakukannya tidak mencegah banyak perpustakaan standar bahasa lainnya menyediakan fungsi penggabungan. Argumen umum yang sama dapat dikatakan tentang penyortiran, namun Elisp menyediakan fungsi penyortiran.

  1. "Bisakah kamu menguraikan?" / "Silakan tentukan perilaku yang Anda cari dengan tepat."

Secara umum, saya terbuka untuk apa yang digunakan oleh komunitas Elisp. Jika Anda ingin contoh tertentu, berikut ini akan menjadi salah satu contoh yang berfungsi:

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

Dan kembali

'(k1 1 k2 2 k3 0))

Ini akan menjadi gaya kemenangan paling kanan, seperti gabungan Clojure.

  1. "Itu daftar, jadi tambahkan saja?"

Tidak, appendtidak memelihara semantik daftar properti . Ini:

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

Mengembalikan ini:

(k1 1 k2 2 k2 0)

append adalah fungsi bawaan di `kode sumber C '.

(tambahkan & sisanya URUTAN)

Gabungkan semua argumen dan buat hasilnya daftar. Hasilnya adalah daftar yang elemen-elemennya adalah elemen dari semua argumen. Setiap argumen dapat berupa daftar, vektor, atau string. Argumen terakhir tidak disalin, hanya digunakan sebagai ekor dari daftar baru.

  1. "Dan contoh Anda tidak menampilkan sesuatu seperti gabungan - bahkan tidak menampilkan dua daftar properti."

Ya itu benar; itu menggabungkan langkah demi langkah. Ini menunjukkan bagaimana melakukan penggabungan menggunakan fungsi daftar properti Elisp yang didokumentasikan sangat menyakitkan:

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

Cukup tampilkan nilai output yang dihasilkan dari pl:

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

Untuk mengulangi, saya mampu menulis fungsi untuk menyelesaikan masalah ini, tetapi saya pertama-tama ingin mencari tahu apakah fungsi tersebut ada di suatu tempat yang umum digunakan.

Akhirnya, jika Anda menolak pertanyaan karena ternyata tidak jelas, saya akan meminta Anda mempertimbangkan kembali sekarang karena saya telah berupaya untuk mengklarifikasi. Ini bukan kurangnya penelitian. Dokumentasi Elisp pada "Daftar" tidak menjawab pertanyaan.


2
Itu daftar, jadi adil append?
abo-abo

2
Silakan tentukan perilaku yang Anda cari dengan tepat. Ada banyak cara untuk "menggabungkan" dua daftar. Dan contoh Anda tidak menampilkan sesuatu seperti penggabungan - bahkan tidak menampilkan dua daftar properti. Sejauh ini, pertanyaan ini harus ditutup sebagai tidak jelas. FWIW, ketahuilah bahwa pasangan yang lebih dekat ke bagian depan plist akan membayang- kan pasangan mana pun yang memiliki kunci yang sama yang lebih jauh dari depan. Jadi penggabungan dapat berarti menempatkan elemen dari satu pelat sebelum elemen dari yang lain, dll.
Drew

1
@ abo-abo: Ternyata Manual Lis Emacs secara eksplisit menyatakan bahwa nama properti harus berbeda .
Constantine

3
Untuk membuat daftar paling kanan menang, Anda hanya perlu membalik urutan daftar yang Anda berikan append: (let ((args '((:a 1 :b 1) (:b 2) (:a 3)))) (apply #'append (reverse args))) => (:a 3 :b 2 :a 1 :b 1)yang sama (:a 3 :b 2 :a 1)selama Anda hanya menggunakan fungsi plist untuk mengakses daftar.
tarsius

1
@Constantine: benar, meskipun tampaknya plist-gettidak plist-memberpeduli atau ada beberapa kunci identik. Sepertinya mereka berperilaku analog ke alists dalam hal ini: (plist-get '(:a "a" :b "b" :a "c") :a) ==> "a". Sementara itu, (plist-put '(:a "a" :b "b" :a "c") :a "d")mengganti nilai :akunci pertama tetapi bukan yang kedua.
Dan

Jawaban:


8

Org-mode, yang disertakan dengan Emacs, memiliki fungsi penggabungan 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))

Untuk menggunakannya Anda harus (require 'org)memuat file terlebih dahulu. Sayangnya, ini adalah file yang sangat besar, 900 + KB, jadi itu tidak benar-benar dapat digunakan sebagai pustaka utilitas. Sesuatu seperti paket plist standar akan menyenangkan untuk dimiliki.

Saya memulai yang sangat kecil baru-baru ini dan menyadari bahwa daftar dan daftar tidak diperlakukan sama, argumen-bijaksana - misalnya (daftar-dapatkan DAFTAR KUNCI) vs. .

Tapi, ya, Emacs membutuhkan perpustakaan plist yang bagus - saya tidak menemukan satu pun dalam pencarian saya, tetapi masih mungkin ada satu di luar sana, kalau tidak kita harus memulainya dan meletakkannya di Elpa / Melpa .

Pustaka alist dengan antarmuka yang sama akan menyenangkan untuk dimiliki juga.


6

Membaca manual dan menelusuri daftar dari C-u C-h a plist RETtidak muncul fungsi apa pun untuk menggabungkan dua daftar properti. Ekstensi Common Lisp tidak menyediakan fungsi apa pun secara khusus untuk bertindak pada daftar properti, hanya dukungan tempat ( getf/ setf/ ...). Jadi, Anda harus mengandalkan perpustakaan pihak ketiga atau menggulir perpustakaan Anda sendiri.

Memutar sendiri tidak terlalu sulit. Implementasi ini menggunakan nilai terakhir jika terjadi konflik.

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

bagus. Mengapa Anda copy-sequenceyang pertama tetapi tidak yang lain? Dan juga, Anda bisa sedikit membersihkan sarang dengan cadrdan cddr.
Dari

sebenarnya, org-combine-plists(di bawah) lebih atau kurang versi yang dibersihkan. Saya masih tidak mengerti mengapa mereka copy-sequencemobil.
Mulai

0

Saya tahu ini sudah dijawab, tetapi jika ada yang tertarik, saya mengambil orgimplementasinya dan memainkan sedikit kode golf

(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))))))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.