我正在练习我的编程范例考试和解决问题集我遇到了这个问题。这是在递归反转和连接列表之后的第一个问题,所以我认为有一个优雅的递归解决方案。
我获得了一份清单和一个排列列表。我应该列出每个列表,包括具有指定排列的列表列表。
我有一个例子:
->(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
->((1 3 2) (5 7 6) (a c b))
我甚至不知道如何开始。我需要在递归解释中制定问题以便能够解决它,但我无法弄清楚如何。
答案 0 :(得分:2)
好吧,让我们看看我们如何解决这个问题。我们给出了一个列表列表和一个数字列表,我们希望根据数字列表指定的顺序对每个列表进行排序:
=>(permute '((1 2 3) (4 5 6)) '(3 2 1))
'((3 2 1) (6 5 4))
我们可以看到列表列表中的每个列表都可以单独处理,它们的解决方案彼此无关。所以我们可以有一个帮助permute1
处理一个列表的情况,然后使用map
将此函数应用于每个列表(每次都有相同的顺序):
(define (permute lists ordering)
(map (lambda (xs) (permute1 xs ordering))
lists))
(define (permute1 items ordering)
...)
现在,要计算(permute1 '(4 5 6) '(3 2 1))
,我们的意思是:
3
的{{1}}项,因为items
中的第一个数字是ordering
。这形成了基本情况(3),递归情况(1)和重复更深的步骤(2)。所以我们解决方案的草图如下:
3
(define (permute1 items ordering)
(if (empty? ordering)
'()
(let ([next-item ???])
(??? next-item
(permute1 items (rest ordering))))))
表示根据???
中的第一个数字获取项目并将此项目与计算的其余部分相结合。
答案 1 :(得分:0)
我有一个例子:
(permute ('(1 2 3) '(a b c) '(5 6 7)) '(1 3 2)) ((1 3 2) (5 7 6) (a c b))
您提供的语法不正确,并且会导致错误,但您的意思相当清楚。你想要那个
(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
;=> ((1 3 2) (5 7 6) (a c b))
现在,我们不清楚你是如何指出排列的。 '(1 3 2)是一种排列,因为它有一些(基于1的)索引,并指示重新排列元素的方式,或者是因为它实际上是元素的排列第一个清单的第一个清单?例如,
(permute '((x y z) (a b c) (5 6 7)) '(1 3 2))
;=> ((x z y) (5 7 6) (a c b))
也工作?我会假设它会,因为它会使问题更容易。
我甚至不知道如何开始。我需要制定问题 递归解释能够解决它,但我无法想象 如何。
您需要编写一个可以获取索引列表的函数,并返回一个将执行置换的函数。例如,。
(define (make-permutation indices)
…)
这样
((make-permutation '(3 1 2)) '(a b c))
;=> (c a b)
你有一个,听起来你的置换功能非常简单:
(define (permute lists indices)
(let ((p (make-permutation indices)))
(p (map p lists))))
这将处理您在示例中给出的情况,因为(地图p列表)将返回((1 3 2)(abc)(5 7 6) ),然后调用 p ,将返回((1 3 2)(5 7 6)(acb))。如果您需要能够处理更深层次的嵌套列表,则需要实现递归映射函数。
答案 2 :(得分:0)
这是另一个使用高阶函数的选项。这是在函数式语言中思考解决方案的惯用方法 - 我们将问题分解为子问题,使用现有过程解决每个问题,最后我们构成答案:
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
(define (perm lst order)
(foldr (lambda (idx acc)
(cons (list-ref lst (sub1 idx)) acc))
'()
order))
(define (permute lst order)
(if (atom? lst)
lst
(perm (map (lambda (x) (permute x order)) lst)
order)))
我们首先定义atom?
,一个通用谓词和perm
,一个帮助程序,它将根据其中一个参数中指定的顺序对任何给定列表重新排序。它使用foldr
构建输出列表,使用list-ref
来访问列表中的元素,给定其基于0的索引(这就是我们从每个索引中减去一个索引的原因)。
主permute
函数在任意嵌套的输入列表的每个元素上处理(递归)映射perm
,因此我们可以获得所需的结果:
(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
=> '((1 3 2) (5 7 6) (a c b))
答案 3 :(得分:0)
这是我的看法,它似乎比前面的例子更短:
(define (permute lst ord)
(define ord-1 (map sub1 ord)) ; change from 1-based to 0-based indexes
(define (perm elts) ; recursive sub-procedure
(if (list? elts)
(map perm (map (curry list-ref elts) ord-1)) ; list -> recurse
elts)) ; else return unchanged
(perm lst)) ; initial call
测试
> (permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
'((1 3 2) (5 7 6) (a c b))
> (permute '((1 (i permute did) 3) (a b (scheme cool is)) (5 6 7)) '(1 3 2))
'((1 3 (i did permute)) (5 7 6) (a (scheme is cool) b))