วิธีที่ดีที่สุดในการเรียกคืนค่าในรายการ assoc-ซ้อนกัน?


11

สมมติว่าฉันได้รับรายการรองแบบนี้:

(setq x '((foo . ((bar . "llama")
                  (baz . "monkey")))))

barและฉันต้องการให้ค่าที่ ฉันสามารถทำสิ่งนี้:

(assoc-default 'bar (assoc-default 'foo x))

แต่สิ่งที่ฉันชอบจริงๆคือสิ่งที่ยอมรับได้หลายปุ่มเช่น

(assoc-multi-key 'foo 'bar x)

สิ่งนั้นมีอยู่จริงหรือเปล่า ฉันแน่ใจว่าฉันสามารถเขียนได้ แต่ฉันรู้สึกว่า Google-fu ของฉันเพิ่งจะล้มเหลวและฉันไม่พบมัน


FWIW ฉันไม่เห็นรายชื่ออื่นใดซ้อนอยู่ในหน้านี้ ฉันเห็นเอลิสต์ธรรมดา ๆ เท่านั้น และยังไม่ชัดเจนว่าคุณกำลังมองหาพฤติกรรมอะไร คุณบอกว่าไม่มีอะไรที่assoc-multi-keyเกี่ยวกับพฤติกรรมของ สันนิษฐานว่ามันจะค้นหาการจับคู่กับทั้งสองข้อโต้แย้งแรก แต่นั่นคือทั้งหมดที่เราสามารถคาดเดาได้จากสิ่งที่คุณพูด และมันไม่สามารถรับได้อย่างชัดเจนมากกว่าสองปุ่มเนื่องจากอาร์กิวเมนต์ alist (สมมุติx) เป็นปุ่มสุดท้ายไม่ใช่คีย์แรก - ซึ่งแสดงว่ามันไม่มีประโยชน์โดยทั่วไป ลองระบุสิ่งที่คุณกำลังมองหาอย่างแท้จริง
Drew

ฉันยังพบการจัดรูปแบบดั้งเดิมของsetqฟอร์มในตัวอย่างที่สับสนดังนั้นฉันจึงแก้ไขเพื่อใช้เครื่องหมายจุดทั่วไปสำหรับรายการ assoc
paprika

อาโอเค. ดังนั้นอลิสต์จะมีสองระดับ คำถามยังไม่ชัดเจน - assoc-multi-keyยังไม่ระบุรายละเอียด
Drew

1
Drew: ประเด็นassoc-multi-keyคือเพื่อค้นหาคีย์แรกในรายการ assoc นี่ควรแก้ไขเป็นรายการ assoc ใหม่ที่เราค้นหาคีย์ถัดไป และอื่น ๆ โดยทั่วไปแล้วมือสั้นสำหรับการขุดค่าออกมาจากรายการ assoc ที่ซ้อนกัน
abingham

2
@ Malabarba คุณอาจพูดถึงlet-alistด้วย เช่นจะกลับมา(let-alist '((foo . ((bar . "llama") (baz . "monkey")))) .foo.bar) "llama"ฉันเดาว่าคุณเขียนlet-alistหลังจากคำถามถูกถาม แต่มันอยู่ในจิตวิญญาณของคำถามและมูลค่าการกล่าวขวัญ IMO!
YoungFrog

คำตอบ:


15

นี่คือตัวเลือกที่ใช้ไวยากรณ์ที่แน่นอนที่คุณขอ แต่ในลักษณะทั่วไปและค่อนข้างง่ายที่จะเข้าใจ ความแตกต่างเพียงอย่างเดียวก็คือALISTพารามิเตอร์จะต้องมาก่อน (คุณสามารถปรับให้เข้ากับสภาพได้หากจำเป็นสำหรับคุณ)

(defun assoc-recursive (alist &rest keys)
  "Recursively find KEYs in ALIST."
  (while keys
    (setq alist (cdr (assoc (pop keys) alist))))
  alist)

จากนั้นคุณสามารถโทรหาด้วย:

(assoc-recursive x 'foo 'bar)

2
นี่เป็นสิ่งที่ฉันทำขึ้นมาไม่มากก็น้อย ฉันแปลกใจนิดหน่อยที่นี่ไม่ได้เป็นส่วนหนึ่งของห้องสมุดที่สร้างขึ้นอย่างประหรืออะไรบางอย่าง ดูเหมือนว่าจะเกิดขึ้นตลอดเวลาเมื่อจัดการกับเช่นข้อมูล json
abingham

2

นี่คือทางออกทั่วไปเพิ่มเติม:

(defun assoc-multi-key (path nested-alist)
   "Find element in nested alist by path."
   (if (equal nested-alist nil)
       (error "cannot lookup in empty list"))
   (let ((key (car path))
         (remainder (cdr path)))
     (if (equal remainder nil)
         (assoc key nested-alist)
       (assoc-multi-key remainder (assoc key nested-alist)))))

มันสามารถใช้ "เส้นทาง" ของคีย์ใด ๆ สิ่งนี้จะกลับมา(bar . "llama")

(assoc-multi-key '(foo bar)
    '((foo (bar . "llama") (baz . "monkey"))))

ในขณะที่สิ่งนี้จะกลับมา(baz . "monkey"):

(assoc-multi-key '(foo bar baz)
    '((foo (bar (bozo . "llama") (baz . "monkey")))))

3
เตรียมพร้อมโหวตลงครั้งแรกของฉันสำหรับคำตอบนี้ ใครยินดีบอกทำไม
rekado

1
ฉันไม่เห็นด้วยกับ downvote เนื่องจากรหัสของคุณใช้งานได้ (+1) การคาดเดาของฉันคือคำตอบของ @ Malabarba ชัดเจนกว่า / ดูดีกว่าคำตอบอื่น ๆ ที่เสนอและคำตอบอื่น ๆ ที่ได้รับไม่ใช่เพราะพวกเขาไม่ทำงาน แต่เพราะพวกเขาไม่ได้ดีที่สุด (ที่ถูกกล่าวว่าฉันชอบ "upvote ที่ดีที่สุดสำหรับตัวเลือก" มากกว่า "upvote ที่ดีที่สุดและ downvote คนอื่น ๆ" ทางเลือก.)
แดน

1
ทั้งสองคำถามถูกลดระดับลงเนื่องจากมีบุคคลหนึ่งที่นี่ที่ไม่เข้าใจวิธีการทำงานของ downvote มาก (และเลือกที่จะไม่สนใจคำขอของอินเทอร์เฟซเพื่อแสดงความคิดเห็น) มันโชคร้าย แต่สิ่งที่ดีที่สุดที่เราทำได้คือการโหวตขึ้น
Malabarba

0

นี่เป็นฟังก์ชั่นพื้นฐานที่ทำงานกับ alist ซ้อนกันภายใน alist อื่น:

(defun assoc2 (outer inner alist)
  "`assoc', but for an assoc list inside an assoc list."
  (assoc inner (assoc outer alist)))

(setq alist2 '((puppies (tail . "waggly") (ears . "floppy"))
               (kitties (paws . "fuzzy")  (coat . "sleek"))))

(assoc2 'kitties 'coat alist2)       ;; => (coat . "sleek")
(cdr (assoc2 'kitties 'coat alist2)) ;; => "sleek"

3
โปรดคนเมื่อคุณลงคะแนนแสดงความคิดเห็น
Malabarba

1
ใครก็ตามที่ลงคะแนน: ฉันไม่ได้โกรธเคือง แต่ฉันสงสัยว่าทำไม @ Malabara: ตอนนี้มีเมตาดาต้าเกี่ยวกับบรรทัดฐานของ "downvote + comment"? ; ฉันอยากรู้เกี่ยวกับสิ่งที่คุณทำ
แดน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.