从方案中的列表中打印对
printing pairs from a list in scheme
我正在尝试从一个列表中打印对,有点像 scheme 中的一个子集,但有两个元素,就像这样
(1 2 3 4 5)
((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5))
我写的代码不起作用
(define (subset x)
(if ( null? x) x
(map cons x (subset (cdr x)))))
这只是 return 一个空列表
在 #lang racket
中这很容易,因为我们有 combinations
:
(combinations '(1 2 3 4 5) 2)
; ==> ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5))
现在这不会打印任何东西。要将其打印到终端,您可以使用 displayln
:
(displayln (combinations '(1 2 3 4 5) 2))
; ==> #<void>, ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5)) printed to terminal as side effect
我更喜欢显式地编写 lambda,这样更容易理解传递的参数:
(define subset
(lambda (lst)
(if (null? lst)
lst
(append (map (lambda (el) (cons (car lst) el)) (cdr lst))
(subset (cdr lst)))
)))
(subset '(1 2 3 4 5))
=> ((1 . 2) (1 . 3) (1 . 4) (1 . 5) (2 . 3) (2 . 4) (2 . 5) (3 . 4) (3 . 5) (4 . 5))
编辑: 下面关于 map 的解释仅在某些版本的方案中有效,请阅读 Sylwester 对此答案的评论。
map 遍历提供给它的 n 个列表,并将 proc
应用于列表中相同位置的 n 个元素。这意味着它可以应用 proc
不超过最短列表长度的次数,但是你一直给它一个空列表(从最后一个递归调用向后)。
(顺便说一句,这是简单的 scheme
)
如果项目的顺序也很重要,可以使用以下内容:
(define (subsets l)
(let loop ((n 0) ; run a loop for each item
(ol '())) ; start with blank output list
(cond
[(= n (length l)) (reverse ol)] ; output ol when last item reached;
[else
(let* ((x (list-ref l n)) ; get one item
(jl (for/list ((i l) ; get remaining list
(j (in-naturals))
#:unless (= j n))
i))
(kl (for/list ((i jl)) ; make combinations with each of remaining list
(list x i))))
(loop (add1 n) (cons kl ol)))])))
测试:
(subsets '(1 2 3 4 5))
输出:
'(((1 2) (1 3) (1 4) (1 5))
((2 1) (2 3) (2 4) (2 5))
((3 1) (3 2) (3 4) (3 5))
((4 1) (4 2) (4 3) (4 5))
((5 1) (5 2) (5 3) (5 4)))
我正在尝试从一个列表中打印对,有点像 scheme 中的一个子集,但有两个元素,就像这样
(1 2 3 4 5)
((1 2) (1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 4) (3 5) (4 5))
我写的代码不起作用
(define (subset x)
(if ( null? x) x
(map cons x (subset (cdr x)))))
这只是 return 一个空列表
在 #lang racket
中这很容易,因为我们有 combinations
:
(combinations '(1 2 3 4 5) 2)
; ==> ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5))
现在这不会打印任何东西。要将其打印到终端,您可以使用 displayln
:
(displayln (combinations '(1 2 3 4 5) 2))
; ==> #<void>, ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5)) printed to terminal as side effect
我更喜欢显式地编写 lambda,这样更容易理解传递的参数:
(define subset
(lambda (lst)
(if (null? lst)
lst
(append (map (lambda (el) (cons (car lst) el)) (cdr lst))
(subset (cdr lst)))
)))
(subset '(1 2 3 4 5))
=> ((1 . 2) (1 . 3) (1 . 4) (1 . 5) (2 . 3) (2 . 4) (2 . 5) (3 . 4) (3 . 5) (4 . 5))
编辑: 下面关于 map 的解释仅在某些版本的方案中有效,请阅读 Sylwester 对此答案的评论。
map 遍历提供给它的 n 个列表,并将 proc
应用于列表中相同位置的 n 个元素。这意味着它可以应用 proc
不超过最短列表长度的次数,但是你一直给它一个空列表(从最后一个递归调用向后)。
(顺便说一句,这是简单的 scheme
)
如果项目的顺序也很重要,可以使用以下内容:
(define (subsets l)
(let loop ((n 0) ; run a loop for each item
(ol '())) ; start with blank output list
(cond
[(= n (length l)) (reverse ol)] ; output ol when last item reached;
[else
(let* ((x (list-ref l n)) ; get one item
(jl (for/list ((i l) ; get remaining list
(j (in-naturals))
#:unless (= j n))
i))
(kl (for/list ((i jl)) ; make combinations with each of remaining list
(list x i))))
(loop (add1 n) (cons kl ol)))])))
测试:
(subsets '(1 2 3 4 5))
输出:
'(((1 2) (1 3) (1 4) (1 5))
((2 1) (2 3) (2 4) (2 5))
((3 1) (3 2) (3 4) (3 5))
((4 1) (4 2) (4 3) (4 5))
((5 1) (5 2) (5 3) (5 4)))