#lang racket
(define (cartesian-product . lists)
(foldr (lambda (xs ys)
(append-map (lambda (x)
(map (lambda (y)
(cons x y))
ys))
xs))
'(())
lists))
(cartesian-product '(1 2 3) '(5 6))
I have racket lang code, that calculate cartesian product of two sets or lists, I don't understand the code well, can any one convert code to pseudo code.
The function corresponds to this definition of cartesian products.
The dot . in the argument means that lists will collect all the arguments (in a list) no matter how many are passed in.
How to call such a function? Use apply. It applies a function using items from a list as the arguments: (apply f (list x-1 ... x-n)) = (f x-1 ... x-n)
foldr is just an abstraction over the natural recursion on lists
; my-foldr : [X Y] [X Y -> Y] Y [List-of X] -> Y
; applies fun from right to left to each item in lx and base
(define (my-foldr combine base lx)
(cond [(empty? lx) base]
[else (combine (first lx) (my-foldr func base (rest lx)))]))
Applying the simplifications from 1), 2) and 3) and turning the "combine" function in foldr to a separate helper:
(define (cartesian-product2 . lists)
(cond [(empty? lists) '(())]
[else (combine-cartesian (first lists)
(apply cartesian-product2 (rest lists)))]))
(define (combine-cartesian fst cart-rst)
(append-map (lambda (x)
(map (lambda (y)
(cons x y))
cart-rst))
fst))
(cartesian-product2 '(1 2 3) '(5 6))
Let's think about "what" combine-cartesian does: it simply converts a n-1-ary cartesian product to a n-ary cartesian product.
We want:
(cartesian-product '(1 2) '(3 4) '(5 6))
; =
; '((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
We have (first lists) = '(1 2) and the result of the recursive call (induction):
(cartesian-product '(3 4) '(5 6))
; =
; '((3 5) (3 6) (4 5) (4 6))
To go from what we have (result of the recursion) to what we want, we need to cons 1 onto every element, and cons 2 onto every element, and append those lists. Generalizing this, we get a simpler reformulation of the combine function using nested loops:
(define (combine-cartesian fst cart)
(apply append
(for/list ([elem-fst fst])
(for/list ([elem-cart cart])
(cons elem-fst elem-cart)))))
To add a dimension, we consed every element of (first lists) onto every element of the cartesian product of the rest.
Pseudocode:
cartesian product <- takes in 0 or more lists to compute the set of all
ordered pairs
- cartesian product of no list is a list containing an empty list.
- otherwise: take the cartesian product of all but one list
and add each element of that one list to every
element of the cartesian product and put all
those lists together.
Related
I have a function that can produce a list of n-element sublists from a list of elements but I am stuck in filtering out elements that are just permutations of each other. For example, f(A,B) -> ((A, B) (B,A)) is what I get but I just want ((A,B)) since (B,A) is a permutation. Is there a lisp function for this? I don't need the whole answer but a clue would be appreciated, note that A,B need not be atoms but can be string literals and even lists themselves.
I am doing this
(let (newlist '())
(loop :for x in l1 :do
(loop :for y in l2 :do
(push (list x y) newlist)))
... and I have another function that filters out these duplicates but it is clunky and probs won't scale for large inputs.
One interesting function is the (destructive) pushnew which pushes an element to a list only if it is not already existent in the set (list).
(defun pair-comb (l1 l2 &key (test #'eql) (key #'identity))
(let ((result '()))
(loop for x in l1 do
(loop for y in l2 do
(pushnew (list x y) result :test test :key key))
finally (return result))))
When we make the comparison between the elements in a way that it is order-agnostic, we would have the perfect function for us to collect different lists while ruling out the permutations of any of the already collected lists.
This can be done by #'sort-ing each list and compare by #'equalp or whatever equality function.
(pair-comb '(1 2 3) '(1 2 3 4 5) :test #'equalp :key (lambda (x) (sort x #'<)))
;;=> ((3 5) (3 4) (3 3) (2 5) (2 4) (2 3) (2 2) (1 5) (1 4) (1 3) (1 2) (1 1))
;; well, actually in this case #'eql would do it.
;; when using non-numeric elements, the `#'<` in sort has to be changed!
I'm trying to understand what count do.
I have read the documentation, and it says:
Returns (length (filter-map proc lst ...)), but without building the
intermediate list.
Then, I have read filter-map documentation, and it says:
Returns (filter (lambda (x) x) (map proc lst ...)), but without
building the intermediate list.
Then, I have read filter documentation, and I have understand it.
But, I don't understand filter-map. In particular that(lambda (x) x) in (filter (lambda (x) x) (map proc lst ...)).
What is the different between filter and filter-map?
By the way, the examples of filter and filter-map do the same and that make it more difficult to understand them.
I would say that the key insight here is that in the context of filter, you should read (lambda (x) x) as not-false?. So, the documentation for filter-map could be written to read:
Returns (filter not-false? (map proc lst ...)), but without building the intermediate list, where not-false? can be defined as (lambda (x) x).
The whole point is that if you know filter and map well, then you can explain filter-map like that. If you do not know what filter and map does it will not help you understand it. When you need to learn something new you often need to use prior experience. Eg. I can explain multiplication by saying 3 * 4 is the same as 3 + 3 + 3 + 3, but it doesn't help if you don't know what + is.
What is the difference between filter and filter-map
(filter odd? '(1 2 3 4 5)) ; ==> (1 3 5)
(filter-map odd? '(1 2 3 4 5)) ; ==> (#t #t #t))
The first collects the original values from the list when the predicate became truthy. In this case (odd? 1) is true and thus 1 is an element in the result.
filter-map doesn't filter on odd? it works as if you passed odd? to map. There you get a new list with the results.
(map odd? '(1 2 3 4 5)) ; ==> (#t #f #t #f #t #f)
Then it removes the false values so that you only have true values left:
(filter identity (map odd? '(1 2 3 4 5))) ; ==> (#t #t #t)
Now. It's important to understand that in Scheme every value except #f is true.
(lambda (x) x) is the identity function and is the same as identity in #lang racket. It returns its own argument.
(filter identity '(1 #f 2 #f 3)) ; ==> (1 2 3)
count works the same way as filter-map except it only returns how many element you would have got. Thus:
(count odd? '(1 2 3 4 5)) ; ==> 3
Now it mentions that it is the same as:
(length (filter identity (map odd? '(1 2 3 4 5)))
Execpt for the fact that the the code using map, filter, and length like that creates 2 lists. Thus while count does the same it does it without using map and filter. Now it seems this is a primitive, but you could do it like this:
(define (count fn lst)
(let loop ((lst lst) (cnt 0))
(cond ((null? lst) cnt)
((fn (car lst)) (loop (cdr lst) (add1 cnt)))
(else (loop (cdr lst) cnt))))
I need to create this:
Define a min&max-lists function that consumes a list of lists
(where the type of the elements in the inner list may be any type).
The function returns a list of lists – such that for each inner list (in the
original list) the following is done –
If the list contains at least one number, then the list is replaced with a list of size two, containing the minimum and maximum in the list.
Otherwise, the list is replaced with a null.
For example
written in a form of a test that you can use:
(test (min&max-lists '((any "Benny" 10 OP 8) (any "Benny" OP (2 3))))
=> '((8 10) ()))
(test (min&max-lists '((2 5 1 5 L) (4 5 6 7 3 2 1) ())) >> '((1 5) (1 7) ()))
For now, I have created a function that do it for one list.
How I do it for the list of lists??
for example:
(listhelp '(2 5 1 5 L))
-> : (Listof Number)>>'(1 5)
Given that you have min&max with the strange name listhelp you can use map, use for/list, or roll your own recursion:
(define (min&max-lists lol)
(map min&max lol))
(define (min&max-lists lol)
(for/list ([e (in-list lol)])
(min&max e)))
(define (min&max-lists lol)
(if (null? lol)
'()
(cons (min&max (car lol))
(min&max-lists (cdr lol)))))
I have to write a function in Racket using foldr that will take a list of numbers and remove list elements that are larger than any subsequent numbers.
Example: (eliminate-larger (list 1 2 3 5 4)) should produce (1 2 3 4)
I can do it without using foldr or any higher-order functions but I can't figure it out with foldr. Here's what I have:
(define (eliminate-larger lst)
(filter (lambda (z) (not(equal? z null)))
(foldr (lambda (x y)
(cons (determine-larger x (rest lst)) y)) null lst))
)
(define (determine-larger value lst)
(if (equal? (filter (lambda (x) (>= x value)) lst) lst)
value
null)
)
determine-larger will take in a value and a list and return that value if it is greater than or equal to all elements in the list. If not, it returns null. Now the eliminate-larger function is trying to go through the list and pass each value to determine-larger along with a list of every number after it. If it is a "good" value it will be returned and put in the list, if it's not a null is put in the list. Then at the end the nulls are being filtered out. My problem is getting the list of numbers that follow after the current number in the foldr function. Using "rest lst" doesn't work since it's not being done recursively like that. How do I get the rest of the numbers after x in foldr?
I really hope I'm not doing your homework for you, but here goes ...
How do I get the rest of the numbers after x in foldr?
Because you're consuming the list from the right, you can structure your accumulator such that "the rest of the numbers after x" are available as its memo argument.
(define (eliminate-larger lst)
(foldr
(lambda (member memo)
(if (andmap (lambda (n) (<= member n)) memo)
(cons member memo)
memo))
'()
lst))
(eliminate-larger (list 1 2 3 5 4)) ;; (1 2 3 4)
This is admittedly a naive solution, as you're forced to traverse the entire accumulator with each iteration, but you could easily maintain a max value, in addition to your memo, and compare against that each time through.
Following works:
(define (el lst)
(define (inner x lsti)
(if(empty? lsti) (list x)
(if(<= x (apply max lsti))
(cons x lsti)
lsti)))
(foldr inner '() lst))
(el (list 1 2 3 5 4))
Output:
'(1 2 3 4)
The cond version may be preferable:
(define (el lst)
(define (inner x lsti)
(cond
[(empty? lsti) (list x)]
[(<= x (apply max lsti)) (cons x lsti)]
[else lsti] ))
(foldr inner '() lst) )
Given this sad thing below, which generates all pairs of only two ranges -
[53]> (setq thingie '())
NIL
[54]> (loop for i in (generate-range 0 3) do
(loop for j in (generate-range 4 6) do
(push (list i j) thingie)))
NIL
[55]> thingie
((3 6) (3 5) (3 4) (2 6) (2 5) (2 4) (1 6) (1 5) (1 4) (0 6) (0 5) (0 4))
[56]>
Or, put another way, this generates sort of a two-dimensional discrete layout.
How would I go about building some sort of pairs-generating code that took arbitrary numbers of ranges? (Or generating an n-dimensional discrete layout).
Obviously one solution would be to have a defmacro that took a list-of-lists and built n loops for execution, but that doesn't feel a straightforward way to go.
(defun map-cartesian (fn bags)
(labels ((gn (x y)
(if y (mapc (lambda (i) (gn (cons i x) (cdr y))) (car y))
(funcall fn x))))
(gn nil (reverse bags))))
CL-USER> (map-cartesian #'print '((1 2) (a b c) (x y)))
(1 A X)
(2 A X)
(1 B X)
(2 B X)
(1 C X)
(2 C X)
(1 A Y)
(2 A Y)
(1 B Y)
(2 B Y)
(1 C Y)
(2 C Y)
If you prefer syntax sugar,
(defmacro do-cartesian ((item bags) &body body)
`(map-cartesian (lambda (,item) ,#body) ,bags))
CL-USER> (do-cartesian (x '((1 2) (a b c) (x y)))
(print x))
Edit: (brief explanation)
The first parameter of gn, x, is the partial tuple constructed so far; y is the remaining bags of elements. The function gn extends the partial tuple by iterating over each element i of one of the remaining bags, (car y), to form (cons i x). When there's no remaining bags (the else branch of the if statement), the tuple is completed, so we invoke the supplied function fn on the tuple.
The obvious thing for me would be a recursive function.
If you're thinking of this as a control structure, the macro route is the way to go. If you're thinking of this as a way of generating data, a recursive function is the way to go.
You don't need explicit recursion (or even a macro), this can also be done with a higher-order function:
(defun tuples-from-ranges (range &rest ranges)
(reduce (lambda (acc range)
(mapcan (lambda (sublist)
(mapcar (lambda (elt)
(append sublist (list elt)))
(apply #'generate-range range)))
acc))
ranges
:initial-value (mapcar #'list (apply #'generate-range range))))
The two nested inner higher-order functions (mapcan and mapcar) perform the same function that the two nested loops in your example did. The outer higher-order function reduce will then first combine the values of the first two ranges to pairs, and after that in each invocation of its argument function apply the some process again to the intermediate results from the preceding invocation and the next range.