这是我生成笛卡尔产品的代码:
(defun cartesian-product (LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
COLLECT (LIST X Y))))
我试着用这个输出笛卡尔的一种产品:
(defun cartesian-product-generator (CALLBACK LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
DO(FUNCALL CALLBACK (LIST X Y)))))
但是,当我尝试用以下方法测试它时会出现错误:
(cartesian-product-generator '(A B C))
Error: Too few arguments in call to #<Compiled-function cartesian-product-generator #x30200097E60F>:
1 argument provided, at least 2 required. While executing: cartesian-product-generator, in process listener(1).
我对LISP很陌生,我想知道为什么会有错误,以及如何修复这个错误。最终,我想输出每个笛卡尔乘积每一个函数的调用。
例如,如果列表由((1 1) (1 2) (2 1) (2 2))
组成。我想要生成(1 1)
。然后是(1 2)
。然后是(2 1)
。最后是(2 2)
。
发布于 2018-04-17 20:38:25
您的第一段代码确实正常工作。
(defun cartesian-product (list)
(loop
for x in list
nconc (loop for y in list
collect (list x y))))
使用'(a b c)
调用它将返回一个列表:
((A A) (A B) (A C) (B A) (B B) (B C) (C A) (C B) (C C))
您希望避免构建列表,而使用回调。为了简化,首先尝试只打印元素而不是收集它们。
这意味着您不关心将生成的值返回给调用者:您只想生成它们并在它们可用时立即打印它们。
基本上,您可以用nconc
和collect
关键字替换do
,并添加对print
的调用
(defun cartesian-product (list)
(loop
for x in list
do (loop for y in list
do (print (list x y)))))
使用'(a b c)
对REPL进行快速测试时,应该打印与以前相同的元素,每个元素都位于分隔线上。
现在,您可以简单地概括print
并调用您想要的任何东西:
(defun map-cartesian-product (function list)
(loop
for x in list
do (loop for y in list
do (funcall function (list x y)))))
为了看它是否仍然有效,做一个快速测试:
(map-cartesian-product #'print '(a b c))
这样做的行为应该和以前一样。
因为您只对一个列表进行了副作用的迭代,所以可以使用DOLIST
。
(defun map-cartesian-product (function list)
(dolist (x list)
(dolist (y list)
(funcall function (list x y)))))
同样,您可以测试它是否仍然像以前一样工作。
发布于 2018-04-17 17:15:24
您可能需要查看通过cl-coroutine
提供的quicklisp
库。那么您的cartesian-product
可以编写为
(cl-coroutine:defcoroutine cartesian-product (list)
(loop for x in list
do (loop for y in list
do (cl-coroutine:yield (list x y)))))
一个例子可以是:
(cl-coroutine:with-coroutine (cartesian-product)
(let ((x (list 1 2 3)))
(loop for y = (cartesian-product x)
while y do (print y))))
; outputs (1 1) (1 2) ... (3 3)
发布于 2022-02-17 09:32:45
只想把我的两分钱留在这里。
您也可以使用宏来完成此操作。
(defmacro cartesian-product (lists)
(let* ((indices (loop for i from 1 to (length lists)
collect (gensym (format nil "~a-i-" i))))
(initial-value `(loop for ,(car (last indices)) in ',(car (last lists))
collect `(,,@indices))))
(reduce
(lambda (x y)
`(loop for ,(car x) in ',(cadr x)
nconc ,y))
(mapcar #'list (butlast indices) (butlast lists))
:from-end t
:initial-value initial-value)))
它会随着
(cartesian-product ((H P) (a b c) (1 2 3 5)))
至
(loop for #:|1-i-806| in '(h p)
nconc (loop for #:|2-i-807| in '(a b c)
nconc (loop for #:|3-i-808| in '(1 2 3 5)
collect `(,#:|1-i-806| ,#:|2-i-807| ,#:|3-i-808|))))
和结果
((H A 1) (H A 2) (H A 3) (H A 5) (H B 1) (H B 2) (H B 3) (H B 5) (H C 1) (H C 2) (H C 3) (H C 5)
(P A 1) (P A 2) (P A 3) (P A 5) (P B 1) (P B 2) (P B 3) (P B 5) (P C 1) (P C 2) (P C 3) (P C 5))
我喜欢它,因为它很简单,不需要递归。
https://stackoverflow.com/questions/49869728
复制相似问题