(Scheme)递归函数来计算某些列表的所有可能组合?

时间:2011-04-05 02:30:51

标签: lisp scheme

计算所有可能的列表组合的递归函数的示例是什么?例如,(combine (list 1 2 3) (list 1 2))应返回'((1 1) (1 2) (2 1) (2 2) (3 1) (3 2))

2 个答案:

答案 0 :(得分:3)

这是我的解决方案。要求SRFI 1和26可用。

(define (cartesian-product first . rest)
  (define (iter l result)
    (define (prepend-all x)
      (map (cut cons <> x) l))
    (concatenate (map prepend-all result)))
  (map reverse (fold iter (map list first) rest)))

答案 1 :(得分:2)

这是我的看法;我首先定义一个帮助器concat/map,它接受​​一个列表和一个函数。与常规map一样,它将该函数应用于列表中的每个元素。但与map不同,它使用append来组合结果,而不是cons。这很有用,因为我们希望将单个级别的列表作为答案返回:

(define concat/map
  (lambda (ls f)
    (cond
      [(null? ls) '()]
      [else (append (f (car ls)) (concat/map (cdr ls) f))])))

然后,为两个列表编写combine很简单。您获取第一个列表中的每个元素,然后将每个列表与第二个列表中的元素x组合在一起。由于这会返回第一个列表中每个元素的答案列表,因此请使用concat/map将它们组合在一起:

(define combine
  (lambda (xs ys)
    (concat/map xs (lambda (x)
                     (map (lambda (y) (list x y)) ys)))))

在一个或多个列表上运行的combine版本,我们称之为combine*,有点棘手。我们只是递归地询问所有剩余的x,然后ys cons的产品,而不是将x与第二个列表中的元素组合在一起。每个结果。当只有两个要合并的列表时,递归会停止,并且在这种情况下使用原始combine

(define combine*
  (lambda (xs . ys*)
    (cond
      [(null? ys*) (map list xs)]
      [(null? (cdr ys*)) (combine xs (car ys*))]
      [else (concat/map xs (lambda (x)
                             (map (lambda (y) (cons x y))
                                  (apply combine* ys*))))])))

作为奖励,使用concat/map做一些工作并将得到的答案组合起来的这种模式实际上是list monad。这里简化了,但结构已经到位。