如何在 mapcar 中指定替代参数?

How to specify arguments for substitute in mapcar?

例如,我有一个 "strings" 的列表:("First" "second" "third.").
我需要将所有 "s" 替换为 "a" -> (("Firat")...等 我发现了一个非常漂亮的函数,叫做 substitute,但它只对一个序列有效。
我可以在 mapcar 中使用替代品吗?像这样:

(mapcar 'substitute #\d #\o '(("test") ("wow") ("waow")))

你可以用 LAMBDA 包裹函数:

(mapcar (lambda (string) (substitute #\d #\o string)) '("test" "wow" "waow"))
;=> ("test" "wdw" "wadw")

或者您可以使用名为 CURRY 的辅助函数(它不是 Common Lisp 标准的一部分,但在 Alexandria 中可用)。

(ql:quickload :alexandria)
(use-package :alexandria)
(mapcar (curry #'substitute #\d #\o) '("test" "wow" "waow"))
;=> ("test" "wdw" "wadw")

对于子列表中的多个字符串,可以使用嵌套mapcar/lambda:

(mapcar (lambda (sentence) 
          (mapcar (lambda (string) 
                    (substitute #\d #\o string))
                  sentence))
        '(("I" "like" "my" "dog.") ("My" "dog" "likes" "me" "too.")))
;=> (("I" "like" "my" "ddg.") ("My" "ddg" "likes" "me" "tdd."))

内层的 LAMBDA 也可以改成 CURRY:

(mapcar (lambda (sentence) 
          (mapcar (curry #'substitute #\d #\o) sentence))
        '(("I" "like" "my" "dog.") ("My" "dog" "likes" "me" "too.")))

甚至:

(mapcar (curry #'mapcar (curry #'substitute #\d #\o))
        '(("I" "like" "my" "dog.") ("My" "dog" "likes" "me" "too.")))

我在 jkiiski 的非常好的回答中添加了最后一种可能性,在这种情况下为 substitute 指定参数,尽管它可能不是您需要的:

(mapcar #'substitute '(#\x #\x #\x) '(#\a #\b #\c) '("abcd" "abcd" "abcd"))
;; => ("xbcd" "axcd" "abxd")

这里对于每个 i 直到任何传递列表的最小长度,mapcar 传递第一个列表的第 i 个元素作为第一个参数,[=12=第二个的第 ] 个元素作为第二个参数,第 i 个元素作为 substitute 的第三个参数。这是有效的,因为 mapcar 需要一个或任意数量的列表。

只有当您想对(几乎)每个字符串执行不同的替换时,才有意义。

除了平面列表之外,还可以考虑递归,以处理一般的嵌套情况:

(labels ((my-sub (s)
           (typecase s
             (string (substitute #\d #\o s))
             (list (mapcar #'my-sub s))
             (otherwise s))))
  (my-sub '(("I" "like" "my" "dog.")
        ("My" ("dog" "likes" "me") "too."))))