我如何获得满足 Common Lisp 条件的列表的集合和子集的所有可能组合
How can i get all possible combinations of sets and subsets of a list that satisfy conditions with Common Lisp
对于 L = (A B C D) 的元素列表,要生成满足元素字典顺序 (A < B < C < D ...< Z) 的所有可能的元素组合,将生成所有组合。
例如 L = (A B C D) 井输出 (A), (B), (C), (D), (A B), (B C), (C D), (A B C), (B C D), (A B C D).
看起来你只是写了一个简单的函数来获取列表的幂集,然后删除一个空集,然后以任何你想要的方式对其进行排序。
(defun powerset (lst)
(if lst (mapcan (lambda (el) (list (cons (car lst) el) el))
(powerset (cdr lst)))
'(())))
CL-USER> (powerset '(A B C D))
((A B C D) (B C D) (A C D) (C D) (A B D) (B D) (A D) (D) (A B C) (B C) (A C)
(C) (A B) (B) (A) NIL)
要获得准确的描述输出,您可以删除 NIL 并将其反转:
CL-USER> (reverse (remove nil (powerset '(A B C D))))
((A) (B) (A B) (C) (A C) (B C) (A B C) (D) (A D) (B D) (A B D) (C D) (A C D)
(B C D) (A B C D))
这是你想要的吗?
更新。抱歉,没有提到您希望它以另一种方式排序。你应该求助于它:
CL-USER> (sort
(reverse
(remove nil
(powerset '(A B C D))))
#'< :key #'length)
((A) (B) (C) (D) (A B) (A C) (B C) (A D) (B D) (C D) (A B C) (A B D) (A C D)
(B C D) (A B C D))
这是另一个更重要的解决方案,使用 loop
宏,执行您描述的操作:
(defun combinations (lst)
(loop :for i :below (expt 2 (length lst))
:when (loop :for j :below i :for el :in lst if (logbitp j i) :collect el)
:collect it :into result
:finally (return (sort result #'< :key #'length))))
CL-USER> (combinations '(A B C D E))
((A) (B) (C) (D) (E) (A B) (A C) (B C) (A D) (B D) (C D) (A E) (B E) (C E)
(D E) (A B C) (A B D) (A C D) (B C D) (A B E) (A C E) (B C E) (A D E) (B D E)
(C D E) (A B C D) (A B C E) (A B D E) (A C D E) (B C D E) (A B C D E))
lexicographical(非词典)顺序可以通过以下函数获得,该函数检查列表 a
是否在词典顺序中位于列表 b
之前:
(defun lex<= (a b)
(or (null a)
(and b
(string<= (car a) (car b))
(lex<= (cdr a) (cdr b)))))
所以,你可以产生所有的组合,就像在 coredump 的答案中一样,然后用 (sort result #'lex<=)
.
对它们进行排序
对于 L = (A B C D) 的元素列表,要生成满足元素字典顺序 (A < B < C < D ...< Z) 的所有可能的元素组合,将生成所有组合。 例如 L = (A B C D) 井输出 (A), (B), (C), (D), (A B), (B C), (C D), (A B C), (B C D), (A B C D).
看起来你只是写了一个简单的函数来获取列表的幂集,然后删除一个空集,然后以任何你想要的方式对其进行排序。
(defun powerset (lst)
(if lst (mapcan (lambda (el) (list (cons (car lst) el) el))
(powerset (cdr lst)))
'(())))
CL-USER> (powerset '(A B C D))
((A B C D) (B C D) (A C D) (C D) (A B D) (B D) (A D) (D) (A B C) (B C) (A C)
(C) (A B) (B) (A) NIL)
要获得准确的描述输出,您可以删除 NIL 并将其反转:
CL-USER> (reverse (remove nil (powerset '(A B C D))))
((A) (B) (A B) (C) (A C) (B C) (A B C) (D) (A D) (B D) (A B D) (C D) (A C D)
(B C D) (A B C D))
这是你想要的吗?
更新。抱歉,没有提到您希望它以另一种方式排序。你应该求助于它:
CL-USER> (sort
(reverse
(remove nil
(powerset '(A B C D))))
#'< :key #'length)
((A) (B) (C) (D) (A B) (A C) (B C) (A D) (B D) (C D) (A B C) (A B D) (A C D)
(B C D) (A B C D))
这是另一个更重要的解决方案,使用 loop
宏,执行您描述的操作:
(defun combinations (lst)
(loop :for i :below (expt 2 (length lst))
:when (loop :for j :below i :for el :in lst if (logbitp j i) :collect el)
:collect it :into result
:finally (return (sort result #'< :key #'length))))
CL-USER> (combinations '(A B C D E))
((A) (B) (C) (D) (E) (A B) (A C) (B C) (A D) (B D) (C D) (A E) (B E) (C E)
(D E) (A B C) (A B D) (A C D) (B C D) (A B E) (A C E) (B C E) (A D E) (B D E)
(C D E) (A B C D) (A B C E) (A B D E) (A C D E) (B C D E) (A B C D E))
lexicographical(非词典)顺序可以通过以下函数获得,该函数检查列表 a
是否在词典顺序中位于列表 b
之前:
(defun lex<= (a b)
(or (null a)
(and b
(string<= (car a) (car b))
(lex<= (cdr a) (cdr b)))))
所以,你可以产生所有的组合,就像在 coredump 的答案中一样,然后用 (sort result #'lex<=)
.