【发布时间】:2010-11-14 22:36:42
【问题描述】:
是否可以仅使用基本方案构造来生成列表的 n 大小排列?
【问题讨论】:
-
没有
define或letrec(或至少lambda)? -
“有没有可能...” 鉴于您的允许构造集是图灵完备的,任何事情都是可能的。
标签: permutation
是否可以仅使用基本方案构造来生成列表的 n 大小排列?
【问题讨论】:
define 或letrec(或至少lambda)?
标签: permutation
使用define,您可以这样做(如果没有define,答案是否定的,因为您需要使用递归):
首先定义一个函数,该函数接受一个列表列表和一个值,并返回一个列表列表,其中给定项目已预先添加到原始列表列表中的每个列表。
这可以通过编写一个简单的递归函数来完成,该函数使用cons 将项目添加到第一个列表(使用car 获取第一个列表),然后再次使用cons 到prepend 扩展list 到在其他列表上调用函数的结果(即在列表列表的cdr 上)。如果列表为空(因此没有car 和cdr),则返回空列表。
您还需要一个从列表中删除给定项目的函数。这也可以通过定义一个接受项目和列表的简单递归函数来完成。在每个步骤中,如果给定列表的“汽车”不等于要删除的项目,则应将其添加到递归调用的结果之前。如果相等,则直接返回递归调用的结果。
您还需要一个函数来连接列表。这也可以递归实现,没有太多麻烦。
然后定义一个函数,给定一个列表列表和一个项目,以项目和每个子列表作为其参数调用前一个函数。
现在定义一个创建 n 大小排列的函数。这个函数应该接受数字n 和一个列表。如果n 为0,它应该返回空列表。否则,它应该为列表中的每个项目x 递归调用自身,其中(- n 1) 作为n 的新值,并且从列表中删除x 的结果作为列表的新值。那么递归调用的结果应该被连接起来。
【讨论】:
这是对Rosetta 中代码的解释,不过,我更改了变量名称以使其更具可读性,并在下面添加了我对代码的解释。我确实检查了代码是否在 DrRacket 中有效,并且确实有效。
在定义 permute 之前,需要两个辅助函数,即 seq 和 insert。
seq 构建一个包含数字序列的列表。例如 (seq 0 3) -> (0 1 2 3)。 列表中的元素 (numbers) 在 insert 函数中用于将 carItem 插入到 'cdr'列表。
(define (seq start end)
(if (= start end)
(list end) ; if start and end are the same number, we are done
(cons start (seq (+ start 1) end))
)
)
insert 生成一个列表,其中 carItem 插入到 cdrList 的第“n”个位置。例如,(insert '(b c) 0 'a) -> '(a b c) 和 (insert '(b c) 2 'a) -> '(b c a)。
(define (insert cdrList n carItem)
(if (= 0 n)
(cons carItem cdrList) ; if n is 0, prepend carItem to cdrList
(cons (car cdrList)
(insert (cdr cdrList) (- n 1) carItem))))
最后,对于主函数permute,它以递归的方式使用insert和seq。 例如,当 plist = '(b,c) lambda eval 为以下内容:
; (map (lambda (n)
; (insert '(b c) n 'a))
; '(0 1 2)) -> output of seq function given n = 2, which is length of '(b c)
; '((a b c) (b a c) (b c a)) ---> will be the output
(define (permute mylist)
(if (null? mylist)
'(())
(apply append (map (lambda (plist)
(map (lambda (n)
(insert plist n (car mylist)))
(seq 0 (length plist))))
(permute (cdr mylist))))))
(permute '(a b c))
如果上面的嵌套 lambdas 让您头晕目眩(对我来说确实如此),请在下面找到,恕我直言,这是一个更易读的“定义”版本,感谢 Matthias Felleisen:
(define (permute mylist)
(cond
[(null? mylist) '(())]
[else
(define (genCombinationsFor plist)
(define (combineAt n) (insert plist n (car mylist)))
(map combineAt (seq 0 (length plist))))
(apply append (map genCombinationsFor (permute (cdr mylist))))]))
【讨论】: