从方案中的列表中打印对

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)))