ฟังก์ชั่นการรวมสองรายการคุณสมบัติ?


11

ฉันไม่พบฟังก์ชันไลบรารี Elisp มาตรฐานเพื่อรวมสองรายการคุณสมบัติเช่นนี้:

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

ฉันสามารถสร้างบางอย่างด้วยdolistแต่ก่อนที่ฉันจะทำฉันต้องการตรวจสอบว่าฉันไม่ได้มองเห็นฟังก์ชั่นที่มีอยู่ในห้องสมุดบางแห่ง

อัพเดทตามความคิดเห็น :

  1. ในการตอบสนองต่อความคิดเห็น "หลายวิธี":

ฉันคิดว่าไม่มีฟังก์ชั่นดังกล่าวเพราะมีคำตอบที่แตกต่างกัน (และอาจเป็นไปได้) สำหรับคำถาม: จะทำอย่างไรเมื่อคุณมีชื่อคุณสมบัติที่ซ้ำกันด้วยค่าที่แตกต่างกัน?

ใช่มีคำถามเกี่ยวกับวิธีการรวมรายการที่ซ้ำกัน แต่มีวิธีการค่อนข้างน้อยในการจัดการ ฉันเห็นสองแนวทางทั่วไป ขั้นแรกคำสั่งอาร์กิวเมนต์สามารถแก้ไขรายการที่ซ้ำได้ เช่นขวาสุดชนะในขณะที่การผสาน Clojure ของ ประการที่สองการผสานอาจมอบหมายให้ผู้ใช้ที่ให้ฟังก์ชั่นการโทรกลับในขณะที่การผสานทับทิม

ไม่ว่าในกรณีใดความจริงที่ว่ามีวิธีการทำที่แตกต่างกันก็ไม่ได้ป้องกันไม่ให้ห้องสมุดมาตรฐานภาษาอื่น ๆ อีกมากมายไม่สามารถจัดเตรียมฟังก์ชันการผสานได้ อาร์กิวเมนต์ทั่วไปเดียวกันสามารถพูดได้ของการเรียงลำดับและยัง 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)

ผนวกเป็นฟังก์ชั่นในตัวใน `ซอร์สโค้ด C '

(ผนวกและพักผ่อน SEQUENCES)

เชื่อมอาร์กิวเมนต์ทั้งหมดและสร้างผลลัพธ์เป็นรายการ ผลที่ได้คือรายการที่มีองค์ประกอบเป็นองค์ประกอบของการขัดแย้งทั้งหมด แต่ละอาร์กิวเมนต์อาจเป็นรายการเวกเตอร์หรือสตริง อาร์กิวเมนต์สุดท้ายไม่ถูกคัดลอกใช้เป็นส่วนท้ายของรายการใหม่

  1. "และตัวอย่างของคุณไม่แสดงอะไรเลยเหมือนกับการผสาน - มันไม่แสดงรายการคุณสมบัติสองรายการ"

ใช่; มันรวมขั้นตอน มันแสดงให้เห็นว่าการผสานโดยใช้ฟังก์ชั่นรายการคุณสมบัติของเอกสารของ 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

2
โปรดระบุพฤติกรรมที่คุณต้องการอย่างแม่นยำ มีหลายวิธีในการ "ผสาน" สองรายการ และตัวอย่างของคุณไม่แสดงอะไรเลยเหมือนการผสาน - มันไม่ได้แสดงสองรายการคุณสมบัติ จนถึงตอนนี้คำถามนี้ควรปิดอย่างชัดเจน FWIW โปรดระวังว่าคู่ที่อยู่ใกล้กับด้านหน้าของเงาจะมีคู่ที่มีคีย์เดียวกันซึ่งอยู่ไกลจากด้านหน้า ดังนั้นการรวมกันอาจหมายถึงการวางองค์ประกอบจาก Plist หนึ่งก่อนที่องค์ประกอบจากอื่น ๆ
Drew

1
@ Abo-Abo: มันปรากฎว่าEmacs เสียงกระเพื่อมคู่มือการใช้งานอย่างชัดเจนระบุว่าชื่อคุณสมบัติจะต้องแตกต่าง
Constantine

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

1
@Constantine: ขวาแม้ว่าค่าplist-getมิได้plist-memberดูเหมือนจะดูแลถ้ามีคีย์ที่เหมือนกันหลาย ดูเหมือนว่าพวกเขามีพฤติกรรมคล้ายคลึงกับ alists ในแง่นี้: (plist-get '(:a "a" :b "b" :a "c") :a) ==> "a". ในขณะเดียวกัน(plist-put '(:a "a" :b "b" :a "c") :a "d")แทนที่ค่าของ:aคีย์แรกแต่ไม่ใช่ที่สอง
ด่าน

คำตอบ:


8

Org-mode ซึ่งมาพร้อมกับ Emacs มีฟังก์ชั่นการผสานแบบ 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) vs (assoc KEY LIST) ซึ่งต้องมีบางอย่างที่โชคร้ายของการเพิ่มประสิทธิภาพ (หรือ?) .

แต่ใช่ Emacs ต้องการไลบรารี plist ที่ดี - ฉันไม่ได้เจอหนึ่งในการค้นหาของฉัน แต่ก็ยังมีความเป็นไปได้ที่จะมีหนึ่งที่นั่นหรืออื่น ๆ เราจะต้องเริ่มต้นหนึ่งและวางไว้บน Elpa / Melpa .

ไลบรารี alist ที่มีอินเตอร์เฟสเดียวกันก็น่าจะมีเช่นกัน


6

การอ่านคู่มือและเรียกดูรายการจากC-u C-h a plist RETจะไม่เปิดฟังก์ชั่นใด ๆ เพื่อรวมสองรายการคุณสมบัติ ส่วนขยาย 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ถึงเป็นคนแรกที่วางแผน แต่ไม่ใช่คนอื่น ๆ ? และยังให้คุณสามารถทำความสะอาดรังบิตด้วยและcadr cddr
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.