JNe*_*ens 1 lisp combinations loops list common-lisp
我试图在Lisp中编写一个函数,生成给定键和值的所有可能组合.这是一个示例输入和输出:
Input: '((key1 . (v1 v2))
(key2 . (v3 v4)))
Output: '(((key1 . v1)(key2 . v3))
((key1 . v1)(key2 . v4))
((key1 . v2)(key2 . v3))
((key1 . v2)(key2 . v4)))
Run Code Online (Sandbox Code Playgroud)
目前,我执行此操作的功能如下:
(defun generate-selectors (selectors)
(cond ((= (length selectors) 0) nil)
((= (length selectors) 1)
(let* ((keys (mapcar #'first selectors))
(key (first keys))
(values (rest (assoc key selectors))))
(loop for val in values
collect (cons key val))))
(t
(let* ((keys (mapcar #'first selectors))
(key (first keys))
(values (rest (assoc key selectors)))
(rest (remove (assoc key selectors) selectors)))
(loop for r in (generate-selectors rest)
append (loop for val in values
collect (cons (cons key val) (list r))))))))
Run Code Online (Sandbox Code Playgroud)
对于上面给出的输入,该函数按预期工作:
> (generate-selectors '((key1 . (v1 v2 v3)) (key2 . (v4 v5))))
(((KEY1 . V1) (KEY2 . V4))
((KEY1 . V2) (KEY2 . V4))
((KEY1 . V3) (KEY2 . V4))
((KEY1 . V1) (KEY2 . V5))
((KEY1 . V2) (KEY2 . V5))
((KEY1 . V3) (KEY2 . V5)))
Run Code Online (Sandbox Code Playgroud)
但是,对于更长的输入,输出不再正确!
> (generate-selectors '((key1 . (v1 v2 v3)) (key2 . (v4 v5)) (key3 . (v6))))
(((KEY1 . V1) ((KEY2 . V4) (KEY3 . V6)))
((KEY1 . V2) ((KEY2 . V4) (KEY3 . V6)))
((KEY1 . V3) ((KEY2 . V4) (KEY3 . V6)))
((KEY1 . V1) ((KEY2 . V5) (KEY3 . V6)))
((KEY1 . V2) ((KEY2 . V5) (KEY3 . V6)))
((KEY1 . V3) ((KEY2 . V5) (KEY3 . V6))))
Run Code Online (Sandbox Code Playgroud)
请注意上面的输出KEY2并KEY3嵌套在另一个子列表中.正确的输出应如下所示:
(((KEY1 . V1) (KEY2 . V4) (KEY3 . V6))
((KEY1 . V2) (KEY2 . V4) (KEY3 . V6))
... )
Run Code Online (Sandbox Code Playgroud)
是什么导致我的generate-selectors功能?
编辑:当没有包装r在列表中时,我得到以下输出:
> (generate-selectors '((key1 . (v1 v2 v3)) (key2 . (v4 v5)) (key3 . (v6))))
(((KEY1 . V1) (KEY2 . V4) KEY3 . V6)
((KEY1 . V2) (KEY2 . V4) KEY3 . V6)
((KEY1 . V3) (KEY2 . V4) KEY3 . V6)
((KEY1 . V1) (KEY2 . V5) KEY3 . V6)
((KEY1 . V2) (KEY2 . V5) KEY3 . V6)
((KEY1 . V3) (KEY2 . V5) KEY3 . V6))
Run Code Online (Sandbox Code Playgroud)
鉴于以前的解决方案是正确的,我想提出一个替代解决方案.给定列表A1,A2,... An,以下函数执行它们的笛卡尔积(A1 x A2 x ... x An):
(defun cartesian-product (l)
(if (null l)
(list nil)
(loop for x in (car l)
nconc (loop for y in (cartesian-product (cdr l)) collect (cons x y)))))
Run Code Online (Sandbox Code Playgroud)
然后该函数generate-selectors可以定义为:
(defun generate-selectors (selectors)
(cartesian-product (loop for s in selectors
collect (loop for val in (cdr s) collect (cons (car s) val)))))
Run Code Online (Sandbox Code Playgroud)