开发者

(Scheme) Recursive function to compute all possible combinations of some lists?

What is an example of a recursive function to compute all possible combinations of lists? For example, (combine (list 1 2 3) (list 1 2)) should return '((开发者_JS百科1 1) (1 2) (2 1) (2 2) (3 1) (3 2)).


Here's my take; I first define a helper concat/map, which takes a list and a function. Like regular map, it applies that function to each element in the list. Unlike map, though, it uses append to combine the results rather than cons. This is useful because we want to get back a single level of lists as an answer:

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

Then, writing combine for two lists is straightforward. You take each element of the first list, then make every list combining it and an element x from the second list. Since this gives back a list of answers for each element in the first list, use concat/map to put it together as we want:

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

The version of combine that operates on one or more lists, let's call it combine*, is a bit trickier. Instead of making all the lists combining x with the elements from the second list, we just recursively ask for the product of all the remaining ys, and then cons x onto each of those results. The recursion stops when there's only two lists to combine, and uses the original combine in that case.

(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*))))])))

As a bonus, this pattern of using concat/map to do some work and combine the resulting answers is actually the list monad. It's simplified here, but the structure is in place.


Here's my solution. Requires SRFIs 1 and 26 to be available.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜