这个lisp函数可以递归实现吗?
Can be this lisp function be implemented recursively?
这个函数的目标是生成2个列表的笛卡尔积。
例如
(组合 (列表 1 2 3) (列表 4 5)) => (1 4) (1 5) (2 4) (2 5) (3 4) (3 5)
(defun combo (l1 l2)
(let (
(res (list))
)
(dolist (elem1 l1 res)
(dolist (elem2 l2 res)
(setq res (append res (list(list elem1 elem2))))
)
)
)
)
如何递归实现?
一个简单的递归实现是使用两个辅助函数;一个遍历 L1
(下面代码中的 %COMBO
),调用另一个函数将一个元素与 L2
(%PRODUCT
)中的每个元素配对:
(defun combo (l1 l2)
(labels ((%product (el list &optional (acc (list)))
(if (endp list)
acc
(%product el (rest list) (cons (list el (first list)) acc))))
(%combo (l1 l2 &optional (acc (list)))
(if (endp l1)
(nreverse acc)
(%combo (rest l1) l2 (nconc (%product (first l1) l2) acc)))))
(%combo l1 l2)))
不过,迭代方法既简单又高效。不要在循环中使用 APPEND
,您应该在最后反转列表。
(defun combo (l1 l2)
(let ((res (list)))
(dolist (e1 l1 (nreverse res))
(dolist (e2 l2)
(push (list e1 e2) res)))))
您也可以只使用 Alexandria 中的 MAP-PRODUCT
函数:
CL-USER> (ql:quickload :alexandria)
;=> (:ALEXANDRIA)
CL-USER> (use-package :alexandria)
;=> T
CL-USER> (map-product #'list (list 1 2 3) (list 4 5))
;=> ((1 4) (1 5) (2 4) (2 5) (3 4) (3 5))
这似乎是 Prolog 的理想选择,尽管数据必须以不同的方式放置:
items1(1).
items1(2).
items1(3).
items2(4).
items2(5).
?- findall((A,B), (items1(A), items2(B)), L).
L = [ (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)].
这个函数的目标是生成2个列表的笛卡尔积。 例如
(组合 (列表 1 2 3) (列表 4 5)) => (1 4) (1 5) (2 4) (2 5) (3 4) (3 5)
(defun combo (l1 l2) (let ( (res (list)) ) (dolist (elem1 l1 res) (dolist (elem2 l2 res) (setq res (append res (list(list elem1 elem2)))) ) ) )
)
如何递归实现?
一个简单的递归实现是使用两个辅助函数;一个遍历 L1
(下面代码中的 %COMBO
),调用另一个函数将一个元素与 L2
(%PRODUCT
)中的每个元素配对:
(defun combo (l1 l2)
(labels ((%product (el list &optional (acc (list)))
(if (endp list)
acc
(%product el (rest list) (cons (list el (first list)) acc))))
(%combo (l1 l2 &optional (acc (list)))
(if (endp l1)
(nreverse acc)
(%combo (rest l1) l2 (nconc (%product (first l1) l2) acc)))))
(%combo l1 l2)))
不过,迭代方法既简单又高效。不要在循环中使用 APPEND
,您应该在最后反转列表。
(defun combo (l1 l2)
(let ((res (list)))
(dolist (e1 l1 (nreverse res))
(dolist (e2 l2)
(push (list e1 e2) res)))))
您也可以只使用 Alexandria 中的 MAP-PRODUCT
函数:
CL-USER> (ql:quickload :alexandria)
;=> (:ALEXANDRIA)
CL-USER> (use-package :alexandria)
;=> T
CL-USER> (map-product #'list (list 1 2 3) (list 4 5))
;=> ((1 4) (1 5) (2 4) (2 5) (3 4) (3 5))
这似乎是 Prolog 的理想选择,尽管数据必须以不同的方式放置:
items1(1).
items1(2).
items1(3).
items2(4).
items2(5).
?- findall((A,B), (items1(A), items2(B)), L).
L = [ (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)].