是否可以仅使用基本方案构造生成列表的n大小的排列?
答案 0 :(得分:0)
使用define
你可以这样做(没有define
答案是否定的,因为你需要使用递归):
首先定义一个获取列表和值列表的函数,并返回列表列表,其中给定项目已添加到原始列表列表中的每个列表中。
这可以通过编写一个简单的递归函数来完成,该函数使用cons
将项目添加到第一个列表(使用car
获取第一个列表),然后再次使用cons
到prepend
扩展列表到在其他列表上调用函数的结果(即在列表列表的cdr
上)。如果列表为空(因此没有car
和cdr
),则返回空列表。
您还需要一个从列表中删除给定项目的函数。这也可以通过定义一个带有项和列表的简单递归函数来完成。在每一步,如果递归调用的结果不等于要删除的项,则应将给定列表的“car”添加到递归调用的结果之前。如果它相等,则应直接返回递归调用的结果。
此外,您还需要一个连接列表的函数。这也可以递归实现而不会有太多麻烦。
然后定义一个给定列表列表的函数,一个项调用前一个函数,并将项目和每个子列表作为参数。
现在定义一个创建n个大小排列的函数。此函数应采用数字n
和列表。如果n
为0,则应返回空列表。否则,它应该为列表中的每个项目x
递归调用自身(- n 1)
作为n
的新值以及从列表中删除x
作为新值的结果列表。然后应该连接递归调用的结果。
答案 1 :(得分:0)
这是对Rosetta中的代码的解释,但是,我已经更改了变量名称以使其更具可读性,并添加了我对下面代码的解释。我确实检查过代码是否在DrRacket中有效,而且确实如此。
在定义 permute 之前,需要两个辅助函数,即 seq 和 insert 。
seq 会构建一个包含一系列数字的列表。例如(seq 0 3) - &gt; (0 1 2 3)。 列表中的元素(数字)用于插入功能,以便在 cdr <中的各个位置插入 carItem / strong>'list。
(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))
)
)
插入会生成一个列表,其中 carItem 插入 cdrList 的第“n”位置。例如,(insert'(b c)0'a) - &gt; '(a b c)和(insert'(b c)2'a) - &gt; '(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))))
最后,对于主要功能置换,它以递归方式使用插入和 seq 。 例如,当plist ='(b,c)时,lambda将证实为:
; (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))))]))