我发现以下代码在Scheme中进行了排列。我的意思是,如果我输入类似参数'(1 2 3),它将给我:
((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))
Run Code Online (Sandbox Code Playgroud)
代码如下:
(define (remove x lst)
(cond
((null? lst) '())
((= x (car lst))(remove x (cdr lst)))
(else (cons (car lst) (remove x (cdr lst))))))
(define (permute lst)
(cond
((= (length lst) 1)(list lst))
(else (apply append(map(lambda (i) (map (lambda (j)(cons i j))
(permute (remove i lst))))lst)))))
Run Code Online (Sandbox Code Playgroud)
第一个函数remove看起来很简单,那就是通过将x与列表的开头进行比较,并与其余部分进行递归调用,从而摆脱x表示的角色,即使它重复与否。
我完全不了解的部分是置换功能。对于我所知道的,map将函数应用于参数的每个元素(在本例中为列表),而对一个参数完全只应用一次函数。那么这行到底是做什么的:
(apply append(map(lambda (i) (map (lambda (j)(cons i j))
(permute (remove i lst))))lst)))))
Run Code Online (Sandbox Code Playgroud)
对我来说,似乎只想创建一个包含两个元素的对:i和j,它们将成为排列了元素的列表(如果我们假设列表只是一堆串联的对)。但是再次调用用i进行置换和清除的部分,该部分在做什么?只是删除列表的头以生成具有固定该对的头的元素i的列表子集,直到用完元素了吗?
有什么帮助吗?
谢谢
让我们从内到外进行区分。修复lst内部表达式并将其应用于其元素之一。
> (define lst '(1 2 3))
> (define i 1)
> (permute (remove i lst))
((2 3) (3 2))
Run Code Online (Sandbox Code Playgroud)
看起来不错:内部表达式删除和元素并递归地生成列表其余部分的排列。现在map,lambda这些排列如下:
> (map (lambda (j) (cons i j)) (permute (remove i lst)))
((1 2 3) (1 3 2))
Run Code Online (Sandbox Code Playgroud)
因此,内部map会产生所有以some开头的排列,i我们已将其设置为1此处。
外层map通过将的所有元素lst视为第一个元素来确保生成所有排列。
> (map (lambda (i) (map (lambda (j) (cons i j))
> (permute (remove i lst))))
> lst)
(((1 2 3) (1 3 2)) ((2 1 3) (2 3 1)) ((3 1 2) (3 2 1)))
Run Code Online (Sandbox Code Playgroud)
但这会产生太多嵌套的列表。应用展append平列表列表,
> (append '(1 2) '(3 4) '(5 6))
(1 2 3 4 5 6)
> (apply append '((1 2) (3 4) (5 6)))
(1 2 3 4 5 6)
Run Code Online (Sandbox Code Playgroud)
因此我们得到了排列的平面清单。