The goal of this function is to generate the cartesian product of 2 list.
For example
(combo (list 1 2 3) (list 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))))
)
)
)
)
How could be implemented recursively?
A simple recursive implementation would be to use two helper functions; one to traverse through L1
(%COMBO
in the code below), calling another function to pair an element with each element from 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)))
The iterative approach is both simpler and more efficient though. Instead of using APPEND
in a loop, you should just reverse the list at the end.
(defun combo (l1 l2)
(let ((res (list)))
(dolist (e1 l1 (nreverse res))
(dolist (e2 l2)
(push (list e1 e2) res)))))
You could also just use the MAP-PRODUCT
function from Alexandria:
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))
It seems ideal for Prolog, though data has to be put differently:
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)].