替换Lisp中的列表子部分的最惯用的方法

时间:2011-07-14 14:19:13

标签: list lisp common-lisp replace

替换列表的特定子序列的最佳方法是什么? 假设我想用(m e)替换子序列i

(sub-substitute 'i '(m e) '(y o u a n d m e))
⇒ (Y O U A N D I)

Nota bene:这与函数substitute非常相似:

(substitute 'u 'i '(i are hungry))
⇒ (U ARE HUNGRY)

1 个答案:

答案 0 :(得分:4)

我不确定这是否是家庭作业,这是一个合法的实际问题,所以我会给你一个简单的解决方案,如果你刚刚被介绍到简单列表,你的老师不会期望并且会很好奇处理。它适用于序列(向量,列表,字符串),并使用一些CL的序列函数:

(defun substitute-subsequence (new old sequence &key (test #'eql))
  (let ((position (search old sequence :test test)))
    (if position
        (concatenate (etypecase sequence
                       (string 'string)
                       (vector 'vector)
                       (list 'list))
                     (subseq sequence 0 position)
                     new
                     (subseq sequence (+ position (length old))))
        sequence)))

然后:

CL-USER> (substitute-subsequence '(i) '(m e) '(y o u a n d m e))
(Y O U A N D I)
CL-USER> (substitute-subsequence #(i) #(m e) #(y o u a n d m e))
#(Y O U A N D I)
CL-USER> (substitute-subsequence "I" "me" "you and me")
"you and I"
CL-USER> (substitute-subsequence "me" "I" "you and I")
"you and me"

如果这是一个家庭作业问题,您应该考虑如何使用您已经介绍过的列表功能来编写特定版本的代码。另外,请注意连接和计算长度在列表上效率不高,应该在紧密循环中避免它。您还可以尝试实现替换所有实例的版本。

编辑:较短版本,可替代所有匹配项,但仅适用于列表:

(defun substitute-sublists (new old list)
  (do ((pos (search old list) (search old list :start2 pos)))
      ((not pos) list)
    (setq list (append (subseq list 0 pos) new (subseq list (+ pos (length old)))))))