方案:给出一个列表和一个排列列表,置换

时间:2014-08-19 15:16:18

标签: recursion functional-programming scheme permutation

我正在练习我的编程范例考试和解决问题集我遇到了这个问题。这是在递归反转和连接列表之后的第一个问题,所以我认为有一个优雅的递归解决方案。

我获得了一份清单和一个排列列表。我应该列出每个列表,包括具有指定排列的列表列表。

我有一个例子:

->(permute '((1 2 3) (a b c) (5 6 7)) '(1 3 2))
->((1 3 2) (5 7 6) (a c b))

我甚至不知道如何开始。我需要在递归解释中制定问题以便能够解决它,但我无法弄清楚如何。

4 个答案:

答案 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)),我们的意思是:

  1. 新列表的第一项将是3的{​​{1}}项,因为items中的第一个数字是ordering
  2. 新名单的其余项目将使用订购中的其余数字来确定。
  3. 如果排序是空列表,则返回空列表。
  4. 这形成了基本情况(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))