list - 生成组合

标签 list loops lisp common-lisp combinations

我正在尝试用 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)))

目前,我执行此操作的功能如下:

(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))))))))

对于上面给出的输入,该函数按预期工作:

> (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)))

但是,对于更长的输入,输出不再正确!

> (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))))

请注意,在上面的输出中,KEY2KEY3 嵌套在另一个子列表中。正确的输出应该是这样的:

(((KEY1 . V1) (KEY2 . V4) (KEY3 . V6))
 ((KEY1 . V2) (KEY2 . V4) (KEY3 . V6))
 ...                                  )

是什么导致我的 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))

最佳答案

鉴于前面的解决方案是正确的,我想提出一个替代方案。给定列表列表 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)))))

那么函数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)))))

关于list - 生成组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48489812/

相关文章:

python - 字典:获取键列表的值列表

javascript - 在React循环中向JSX元素添加 key 的不同方法

c++ - Iterator循环会多次调用end()吗?

lisp - 被普通 lisp 中的文件结束条件弄糊涂了

Lisp - lisp 的元素出现在其他列表中

lisp - 演绎检索器示例

list - 当我运行它时,它声明列表约束未绑定(bind)。这是为什么?

python - 在 Python 中删除和替换多项式的系数

list - R:将列表项转换为对象

python - 如何获取数据集中某些单词的值计数