LISP - 移除元素
Lisp 中从序列中移除元素的现代指南
Section titled “Lisp 中从序列中移除元素的现代指南”Common Lisp 提供了一组强大的函数,用于从序列(如列表和向量)中移除元素。Lisp 中一个关键的区别在于非破坏性函数(它们返回一个新的修改后的序列)和破坏性函数(它们可能会修改原始序列)。本指南涵盖了这些操作的现代最佳实践。
非破坏性移除(最佳实践)
Section titled “非破坏性移除(最佳实践)”非破坏性函数更安全,因为它们不会对原始数据产生副作用。这符合函数式编程原则,并使代码更易于理解。除非您有特定的、已被证实的性能瓶颈,否则应始终优先选择这些函数。
1. remove 函数
Section titled “1. remove 函数”remove 函数创建并返回一个新序列,其中移除了特定项的所有出现。原始序列保持不变。
(remove item sequence &key from-end test test-not start end count key)让我们看一个实际示例。我们将从列表中移除数字 3。
(let ((original-list '(1 2 3 4 3 5))) (let ((new-list (remove 3 original-list))) (format t "Original List: ~a~%" original-list) (format t "New List: ~a~%" new-list)))Original List: (1 2 3 4 3 5)New List: (1 2 4 5)2. remove-if 和 remove-if-not
Section titled “2. remove-if 和 remove-if-not”这些函数更强大,因为它们根据条件(一个谓词函数)而不是特定项来移除元素。
(remove-if predicate sequence &key ...)(remove-if-not predicate sequence &key ...)示例:从列表中移除所有奇数。
;; #'oddp 是一个谓词,对于奇数返回真。(let ((new-list (remove-if #'oddp '(1 2 3 4 5 6 7)))) (format t "List with odd numbers removed: ~a~%" new-list))List with odd numbers removed: (2 4 6)破坏性移除(谨慎使用)
Section titled “破坏性移除(谨慎使用)”delete 和 delete-if 等破坏性函数可能会为了效率而修改原始序列的内存结构(其 cons 单元)。如果该序列在程序的其他地方被共享,这可能会很危险。
破坏性函数的重要最佳实践
Section titled “破坏性函数的重要最佳实践”因为破坏性函数可能会修改列表的第一个元素,列表的起始位置可能会改变。因此,您必须始终使用破坏性函数的返回值,通常是将其重新赋值给原始变量。
;; 正确使用 delete(setq my-list (delete 'a my-list))
;; 错误使用 delete。这可能导致 bug!(delete 'a my-list) ; my-list 的绑定未更新。3. delete 和 delete-if
Section titled “3. delete 和 delete-if”它们是 remove 和 remove-if 的破坏性对应物。
示例:破坏性地从列表中移除偶数。
(let ((my-numbers '(1 2 3 4 5 6 7))) (format t "Original variable before delete-if: ~a~%" my-numbers)
;; 列表在原地修改,我们重新赋值变量。 (setq my-numbers (delete-if #'evenp my-numbers))
(format t "Variable after delete-if: ~a~%" my-numbers))Original variable before delete-if: (1 2 3 4 5 6 7)Variable after delete-if: (1 3 5 7)高级用法::key 参数
Section titled “高级用法::key 参数”key 参数对于处理复杂数据结构非常有用。它允许您指定一个函数,在应用测试之前对每个元素进行调用。
示例:从属性列表 (plists) 中移除所有价格低于 50 的产品。
(let ((products '((:name "apple" :price 30) (:name "banana" :price 60) (:name "orange" :price 45)))) (let ((expensive-products (remove-if (lambda (price) (< price 50)) products :key (lambda (product) (getf product :price))))) (format t "Expensive products: ~a~%" expensive-products)))Expensive products: ((:NAME "banana" :PRICE 60))