การลงลึกใน Lisp List Iteration
: การลบองค์ประกอบตามค่า
เมื่อเขียนโปรแกรมใน Lisp
หนึ่งในงานที่พบบ่อยคือการจัดการรายการตามเกณฑ์บางประการ ความท้าทายทั่วไปเกิดขึ้นเมื่อจำเป็นต้องกรององค์ประกอบจากรายการที่ไม่ตรงตามเงื่อนไขบางประการ ในบล็อกโพสต์นี้ เราจะสำรวจปัญหาเฉพาะเกี่ยวกับการทำซ้ำในรายการใน Lisp
และวิธีการแก้ไขอย่างมีประสิทธิภาพ
ปัญหา: การลบองค์ประกอบในรายการที่ไม่มีประสิทธิภาพ
ปัญหาที่นำเสนอเกี่ยวข้องกับฟังก์ชันที่ออกแบบมาเพื่อลบองค์ประกอบจากรายการที่มีค่ามากกว่าค่าที่กำหนด x
เมื่อพิจารณาโค้ดแล้ว ดูเหมือนว่าจะทำงานไม่เป็นไปตามที่ตั้งใจ นี่คือฟังก์ชันต้นฉบับที่ให้มา:
(defun biggerElems(x xs)
(let ((xst))
(dolist (elem xs)
(if (> x elem)
(setf xst (remove elem xs))))
xst))
ทำไมมันถึงไม่ทำงาน?
เมื่อดูในแวบแรก คุณอาจสังเกตว่าวัตถุประสงค์ที่ตั้งใจของฟังก์ชันคือการสร้างรายการที่ไม่มีองค์ประกอบที่มีค่ามากกว่า x
แต่มีเหตุผลหลักที่ทำให้มันล้มเหลว:
- การใช้งาน
setf
ที่ไม่ถูกต้อง: การดำเนินการsetf xst (remove elem xs)
ตั้งใจให้ปรับปรุงxst
ด้วยผลลัพธ์ของremove
แต่กลับทำเช่นนั้นได้ไม่ถูกต้อง - ตัวแปรที่ไม่ได้รับการตั้งค่า: ตัวแปร
xst
ไม่ได้ถูกตั้งค่าใช้งานอย่างมีประสิทธิภาพ; มันอาจจะกลายเป็นnil
หรือไม่เกี่ยวข้อง - ตรรกะที่ไม่มีประสิทธิภาพ: ฟังก์ชันวนรอบแต่ละองค์ประกอบของรายการและเรียกใช้
remove
ซ้ำแล้วซ้ำเล่า ทำให้มีความไม่ประหยัดในการคำนวณ
แนวทางแก้ไข: วิธียุ้งเข้าที่ง่ายและตรงไปตรงมา
วิธีที่ตรงไปตรงมาที่สุดในการแก้ไขปัญหานี้คือการใช้ฟังก์ชันในตัวของ Lisp
อย่างมีประสิทธิภาพมากขึ้น แทนที่จะวนซ้ำด้วยตนเองและลบองค์ประกอบตามเงื่อนไข เราสามารถใช้ฟังก์ชัน remove-if
ซึ่งออกแบบมาเฉพาะเพื่อกรองรายการตามเงื่อนไข
นี่คือวิธีการดำเนินการ
เราสามารถนิยามฟังก์ชันใหม่ได้ดังนี้:
(defun biggerElems (x xs)
(remove-if (lambda (item) (> item x)) xs))
คำอธิบายของฟังก์ชันที่ปรับปรุง:
remove-if
: ฟังก์ชันนี้ต้องการสองอาร์กิวเมนต์: โพรดิเคต (ในกรณีนี้คือฟังก์ชันลัมบ์ดา) และรายการ มันจะลบองค์ประกอบทั้งหมดจากรายการที่ตรงตามเงื่อนไขของโพรดิเคต — ในกรณีนี้คือองค์ประกอบที่มีค่ามากกว่าx
- ฟังก์ชันลัมบ์ดา: ฟังก์ชันลัมบ์ดา
(lambda (item) (> item x))
กำหนดเงื่อนไข: มันตรวจสอบว่าitem
มากกว่าx
หรือไม่ หากคืนค่าเป็นจริงitem
จะถูกลบจากรายการxs
ข้อดีของแนวทางใหม่
- ประสิทธิภาพ: วิธีการนี้ลดความจำเป็นในการลบแบบวนซ้ำ ทำให้ลดภาระในการคำนวณ
- ความชัดเจน: โค้ดมีความอ่านง่ายและกระชับ เข้าใจได้ง่ายในทันที
- ความถูกต้อง: ด้วยการใช้
remove-if
โดยตรง เรามั่นใจได้ว่าค่าทั้งหมดที่มากกว่าx
จะถูกลบออกอย่างมีประสิทธิภาพโดยไม่มีความยุ่งยากเพิ่มเติม
บทสรุป
เมื่อทำงานกับรายการใน Lisp
การเข้าใจการทำซ้ำและการจัดการรายการถือเป็นสิ่งสำคัญ ความพยายามครั้งแรกในการลบองค์ประกอบที่มีค่ามากกว่าค่าที่กำหนดแสดงให้เห็นถึงหลายจุดบกพร่อง ซึ่งเราได้แก้ไขด้วยวิธีการที่ชัดเจนกว่า ด้วยการใช้ remove-if
เราสามารถบรรลุเป้าหมายของเราได้ง่ายและมีประสิทธิภาพ ช่วยให้โค้ดสะอาดและมีประสิทธิภาพมากยิ่งขึ้น ขอให้สนุกกับการเขียนโปรแกรมใน Lisp
!