(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)))
精彩评论