免责声明:我很确定我已经设法搞砸了一些非常简单的东西,可能是因为我一直在讨论这个问题。 等待一些缓慢的C ++构建时“真正的工作”,所以我的头脑不是 在正确的地方。
看着
What's the most efficient way of generating all possible combinations of skyrim (PC Game) potions?我有一种天真的想法,即在Lisp中它将是一个非常非常简单的递归过滤器,用于生成大小为“n”的所有组合。在R中给出的答案很优雅,很好地展示了语言,但combn(list,n)
方法引起了我的注意。 (http://stat.ethz.ch/R-manual/R-patched/library/utils/html/combn.html)
(defun combn (list n)
(cond ((= n 0) nil)
((null list) nil)
((= n 1) (mapcar #'list list))
(t (mapcar #'(lambda (subset) (cons (car list) subset))
(combn (cdr list) (1- n))))))
(combn '(1 2 3 4 5 6 7 8 9) 3)
((1 2 3) (1 2 4) (1 2 5) (1 2 6) (1 2 7) (1 2 8) (1 2 9))
除此之外,这只会返回第一组组合......我无法准确地将我的脑袋包裹在错误的位置。似乎(= n 1)
案例工作正常,但t
案例应该采取不同的做法,例如从列表中删除(1 2)
并重复?
所以,我试图修复它,变得更糟糕了:
(defun combn (list n)
(cond ((= n 0) nil) ((= n 1) (mapcar #'list list))
((null list) nil)
(t (cons (mapcar #'(lambda (subset) (cons (car list) subset))
(combn (cdr list) (1- n)))
(combn (cdr list) n)))))
这是(t cons(
的错误......我想。但是,如果cons
是错误的答案,我不确定什么是正确的......? (减少使用2来演示输出......)
(combn '(1 2 3 4 5 6 7 8 9) 2)
(((1 2) (1 3) (1 4) (1 5) (1 6) (1 7) (1 8) (1 9))
((2 3) (2 4) (2 5) (2 6) (2 7) (2 8) (2 9))
((3 4) (3 5) (3 6) (3 7) (3 8) (3 9))
((4 5) (4 6) (4 7) (4 8) (4 9))
((5 6) (5 7) (5 8) (5 9))
((6 7) (6 8) (6 9))
((7 8) (7 9))
((8 9))
NIL)
......看起来是正确的,除了无关的嵌套和最后的奖励NIL
。 (我原以为((null list) nil)
会过滤掉那个?)
我做错了什么? : - (
(而且,是否有一个更有效的标准例程?)
答案 0 :(得分:1)
是的,cons
不正确,你需要追加。这也是最后得到NIL
的原因。我不能写Lisp,所以我会给你Haskell:
comb :: Int -> [a] -> [[a]]
comb 0 _ = [[]]
comb k (x:xs) = [x:ys | ys <- comb (k-1) xs] ++ comb k xs
comb _ _ = []
这是短暂而甜蜜的,但效率低下(并且没有检查否定k
)。它经常会尝试选择比列表更长的元素。为了防止这种情况,人们会记录仍有多少元素可用。
comb :: Int -> [a] -> [[a]]
comb 0 _ = [[]]
comb k xs
| k < 0 = []
| k > len = []
| k == len = [xs]
| otherwise = go len k xs
where
len = length xs
go l j ys
| j == 1 = map (:[]) ys
| l == j = [ys]
| otherwise = case ys of
(z:zs) -> [z:ws | ws <- go (l-1) (j-1) zs] ++ go (l-1) j zs
丑陋但有效率。
答案 1 :(得分:1)
使用Common Lisp的解决方案。
请注意,如果传入的列表不能被指定的数字整除,则此版本会故意使用assert
给您一个可持续的错误,但它很容易让它只是放置它任何&#34;剩余的&#34;最后一个较短列表中的项目,或使用error
完全保释,而无法进行交互式修复。
基于方案&#39; srfi-1
,由我调整为CL,并由Rainer Joswig大大改进
(defun split-by (list n &aux length)
"splits a list into multiple lists of length n.
Parameters:
* list - the list to be split
* n - the size of the lists it should be broken into.
Returns:
A list of smaller lists of the specified length (or signals an error).
Examples:
(split-by '(1 2 3 4) 2) ; => ((1 2) (3 4))
(split-by '(1 2 3) 2) ; => not evenly divisible"
(assert (zerop (mod (setf length (length list)) n))
(list)
"list is not evenly divisible by ~A: ~A" n list)
(if (plusp length)
(cons (subseq list 0 n)
(split-by (subseq list n) n))
'()))