I have a union method setup to combine 2 sets of ordered intervals:
(define (union set1 set2)
(cond [(empty? set1) set2]
[(empty? set2) set1]
[(< (caar set1) (caar set2)) (cons (car set1) (union (cdr set1)
set2))]
[else (cons (car set2) (union set1
(cdr set2)))]))
Given 2 lists '((1 3) (5 10) (19 29)) and '((2 4) (17 25) (30 49)) they produce
'((1 3) (2 4) (5 10) (17 25) (19 29) (30 49)) with the code above.
But with the above implementation the overlapping intervals aren't being handled correctly. I am needing to merge the overlapping intervals to produce '((1 3) (2 4) (5 10) (17 29) (30 49)). How could I go about handling these interval merges so that there are no overlaps?
Assuming you're working with half-open intervals [from upto), Racket provides an interval-map module:
An interval-map is a mutable data structure that maps half-open intervals of exact integers to values. An interval-map is queried at a discrete point, and the result of the query is the value mapped to the interval containing the point.
The provided examples:
> (define r (make-interval-map))
> (interval-map-set! r 1 5 'apple)
> (interval-map-set! r 6 10 'pear)
> (interval-map-set! r 3 7 'banana)
> (dict-map r list)
'(((1 . 3) apple) ((3 . 7) banana) ((7 . 10) pear))
Using your example inputs '((1 3) (5 10) (19 29)) and '((2 4) (17 25) (30 49)):
#lang racket/base
(require data/interval-map
racket/list
racket/match
racket/dict)
(define im (make-interval-map))
;; Add your first set
(for ([x '((1 3) (5 10) (19 29))])
(interval-map-set! im (first x) (second x) #f))
;; Add your second set
(for ([x '((2 4) (17 25) (30 49))])
(interval-map-set! im (first x) (second x) #f))
;; The result
(map car (dict-map im list))
;; => '((1 . 2) (2 . 4) (5 . 10) (17 . 25) (25 . 29) (30 . 49))
Related
Im having some problems with racket. The assignment wants me to write a procedure that converts any number from base 10 to base 4, the solution should be written in a list. for example (convert-to-base-four 12) -> (list 3 0)
Now i have written a procedure but it inserts each number in an individual list.
heres my code.
(define (convert-to-base-four number)
(cond
[(<= number 3) (cons number empty)]
[(> number 3) (reverse (list (remainder number 4)
(convert-to-base-four (floor (/ number 4)))))]))
Does anyone know what to do?
Many thanks
AlexKnauth's comment is the one you need to be following – you must define and adhere to a strict domain (input) and codomain (output) for your function
;; from your code
(list Y
(convert-to-base-four X))
It doesn't matter what Y and X are here: if convert-to-base-four returns a list of some value and a recursive call to convert-to-base-four – which returns a list – you're going to end up with a list of lists!
One solution, as another points out, is to use append – but beware, it's a trap
(define (base4 n)
(if (< n 4)
(list n)
(append (base4 (floor (/ n 4)))
(list (remainder n 4)))))
(displayln (base4 12)) ; (3 0)
(displayln (base4 13)) ; (3 1)
(displayln (base4 14)) ; (3 2)
(displayln (base4 15)) ; (3 3)
(displayln (base4 16)) ; (1 0 0)
(displayln (base4 123456)) ; (1 3 2 0 2 1 0 0 0)
A better solution would avoid the costly use of append – here we do that using a named let loop with two loop state variables m and acc
(define (base4 n)
(let loop ((m n) (acc empty))
(if (< m 4)
(cons m acc)
(loop (floor (/ m 4))
(cons (remainder m 4) acc)))))
(displayln (base4 12)) ; (3 0)
(displayln (base4 13)) ; (3 1)
(displayln (base4 14)) ; (3 2)
(displayln (base4 15)) ; (3 3)
(displayln (base4 16)) ; (1 0 0)
(displayln (base4 123456)) ; (1 3 2 0 2 1 0 0 0)
Try to use append on your list :)
Have fun with homework ;)
I need to extract the main diagonal from a square matrix
(1 2 3)
(4 5 6) -> (1 5 9)
(7 8 9)
I have the following code and I need to replace the ... with the appropriate functions.
(define (diag m)
(if (null? m) '()
(cons (... m)
(diag (map ... (... m))))))
Input: (diag '((1 2 3) (4 5 6) (7 8 9)))
Output: (1 5 9)
Any ideas? Thank you!
First of all I created a function that returns n-th element of list (I am not sure if you can use built-in function for it, that's why I created my own bicycle):
(define (nthItem l item currentItem)
(if (null? l) '()
(if (= currentItem item) (car l)
(nthItem (cdr l) item (+ currentItem 1)))))
Then I created a function that you need. I added a parameter "i" that contains current position on a diagonal:
(define (diagPrivate m i)
(if (null? m) '()
(cons (nthItem (car m) i 0)
(diagPrivate (cdr m) (+ i 1)))))
For better appearance I created a wrapper for this function (that looks like your initial function):
(define (diag m)
(diagPrivate m 0))
So you are asking, given you have the list '((1 2 3) (4 5 6) (7 8 9)) how do I get the value 1 from it?
Then you are asking given the same list, how do I get ((4 5 6) (7 8 9)) from it.
Then given that result how do I make a new list using map that only takes the rest of each element list so that the result is ((5 6) (8 9))
The question code looks like came from SO as an answer with VERY easy challenge on how to complete it. Am I right?
The answer is of course just list accessors every beginner schemer should know: cdr x 2 and caar, not necessarily in that order.
Using Racket which is a Scheme dialect:
(define diag '((1 2 3) (4 5 6) (7 8 9)))
(define (getDiagonal l)
(let loop ((l l)
(ol '())
(n 0))
(cond
[(empty? l) (reverse ol)]
[(loop (rest l)
(cons (list-ref (first l) n) ol)
(add1 n))])))
(getDiagonal diag)
Output:
'(1 5 9)
There is for/list loop in Racket which also can be used here:
(for/list ((i (length diag)))
(list-ref (list-ref diag i) i))
In racket a higher order function like map used on two lists does this:
(map list '(1 2 3) '(1 2 3))
> '( (1 1) (2 2) (3 3) )
But I would like a cartesian-product thing like this:
'( (1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3) )
How can I achieve this? Preferably with higher order functions?
Here's a method that totally uses higher-order functions (foldr, append-map, and map; now also with compose1, curry, and curryr):
(define (cartesian-product . lists)
(foldr (lambda (a b)
(append-map (compose1 (curryr map b) (curry cons))
a))
'(())
lists))
Pardon the terrible parameter names. One day I'll come up with something good. :-)
> (require unstable/list)
> (cartesian-product '(1 2 3) '(a b c))
'((1 a) (1 b) (1 c) (2 a) (2 b) (2 c) (3 a) (3 b) (3 c))
See http://docs.racket-lang.org/unstable/list.html#%28def._%28%28lib._unstable%2Flist..rkt%29._cartesian-product%29%29
In SCIP chapter 2.2.3 "Sequences as Conventional Interfaces, authors show us a general way to approach such problem. There is actually a similar example. The book uses flatmap as a common abstraction. The combination of mapping and accumulating with append is so common in this sort of program that we will isolate it as a separate procedure: flatmap. Here is a solution using flatmap:
>(define (flatmap proc seq)
(foldr append '() (map proc seq)))
>(flatmap
(lambda (x)
(map
(lambda (y) (list y x))
'(1 2 3)))
'(a b c))
'((1 a) (2 a) (3 a) (1 b) (2 b) (3 b) (1 c) (2 c) (3 c))
Using SERIES library from CLTL2 appendix A, I want a flat series from nested series. For example:
(map-fn t (lambda (x)
(map-fn t (lambda (y)
(cons x y))
(scan '(1 2 3))))
(scan '(4 5 6)))
=> #Z( #Z( (4 . 1) (4 . 2) (4 . 3) )
#Z( (5 . 1) (5 . 2) (5 . 3) )
#Z( (6 . 1) (6 . 2) (6 . 3) ) )
I want to make this series of series to one series as below:
=> #Z( (4 . 1) (4 . 2) (4 . 3)
(5 . 1) (5 . 2) (5 . 3)
(6 . 1) (6 . 2) (6 . 3) )
If I would have an appropriate series concatenation function, it would be good. Although the series library has CATENATE function, it takes just some series in its &rest parameter. I could
(apply #'catenate list-of-series)
but it accepts a list of series, not series of series. Unfortunately, there are not any functions for folding series, while there are for mapping and filtering. The PRODUCING macro shown on A.4. Primitives section in CLTL2 does not work for me because it also seems not to flatten a nested loop. I cannot use NEXT-OUT macro in nested situation.
(apply #'catenate
(collect (map-fn t (lambda (x)
(map-fn t (lambda (y)
(cons x y))
(scan '(1 2 3))))
(scan '(4 5 6)))))
But that is bit of a cheat. To do it properly in series:
(producing (prod) ((zz (generator (map-fn t (lambda (x)
(map-fn t (lambda (y)
(cons x y))
(scan '(1 2 3))))
(scan '(4 5 6)))))
cur)
(loop
(tagbody
redo
(if (null cur)
(setq cur (generator (next-in zz (terminate-producing)))))
(next-out prod (next-in cur (progn
(setq cur nil)
(go redo)))))))
=> #Z((4 . 1) (4 . 2) (4 . 3)
(5 . 1) (5 . 2) (5 . 3)
(6 . 1) (6 . 2) (6 . 3))
Given a list, how do I process N items at a time? Ruby has each_slice method on the Enumerable that does this; what would be the Lisp equivalent?
Common Lisp's loop can be used for this very nicely, as in the following two examples. The first example loops for (x y z) in a list. However, the default step is cdr (rest), so if the list is (1 2 3 4 5), you get (1 2 3), (2 3 4), etc., for (x y z).
CL-USER> (loop for (x y z) on '(1 2 3 4 5 6 7 8 9 10 11 12)
do (print (list z y x)))
(3 2 1)
(4 3 2)
(5 4 3)
(6 5 4)
(7 6 5)
(8 7 6)
(9 8 7)
(10 9 8)
(11 10 9)
(12 11 10)
(NIL 12 11)
(NIL NIL 12)
NIL
If you do not want the overlap between iterations, specify the stepping function to be something that moves farther down the list. For instance, if you're pulling three elements at a time, use cdddr:
CL-USER> (loop for (x y z) on '(1 2 3 4 5 6 7 8 9 10 11 12) by 'cdddr
do (print (list z y x)))
(3 2 1)
(6 5 4)
(9 8 7)
(12 11 10)
NIL
Implementing partition with this technique
Another answer implemented the counterpart to each_slice using an auxiliary function. However, notice that partition (in that sense) is just each_slice with the identity function. This suggests that we should be able to implement it using the idiom above. The anonymous function
(lambda (list)
(nthcdr n list))
is the step function that we need. Since we do not know how many elements the cells have until run time, we can't bind each element like we did above with (x y z). We do have to match each tail of the list as we step down and extract the subsequence n elements. Here's a loop based implementation of partition.
CL-USER> (defun partition (list cell-size)
(loop for cell on list by #'(lambda (list)
(nthcdr cell-size list))
collecting (subseq cell 0 cell-size)))
PARTITION
CL-USER> (partition '(1 2 3 4 5 6) 2)
((1 2) (3 4) (5 6))
(defun partition-helper (lst acc x)
(if (< (length lst) x)
acc
(partition-helper (subseq lst x) (cons (subseq lst 0 x) acc) x)))
(defun partition (lst x)
(reverse (partition-helper lst '() x)))
Then you can:
[25]> (PARTITION '(1 2 3 4 5 6) 2)
((1 2) (3 4) (5 6))
or:
[26]> (PARTITION '(1 2 3 4 5 6) 3)
((1 2 3) (4 5 6))
and then just mapcar over the list to process it 2 or 3 elements at a time.
If you wanted to split your list on a predicate (as opposed to a fixed length sublists), I would have recommended nsplit-list.
For fixed length sublists, you may want to use loop:
(defun by-N (list n fun)
(loop for tail on list by (lambda (l) (nthcdr n l))
do (funcall fun (subseq tail 0 (min (length tail) n)))))
(by-n (loop for i from 0 to 20 collect i) 5 #'print)
(0 1 2 3 4)
(5 6 7 8 9)
(10 11 12 13 14)
(15 16 17 18 19)
(20)
Note that this is not very efficient (it scans the list more than necessary and allocates a fresh sublist for passing to fun).
The efficient version is more complicated:
(defun batch-map (list batch-size function)
"Call FUNCTION on sublists of LIST of size BATCH-SIZE.
Returns the list of return values of FUNCTION."
(do ((tail list (cdr end)) end ret (bs1 (1- batch-size)))
((endp tail) (nreverse ret))
(setq end (nthcdr bs1 tail))
(if (consp end)
(let ((next (cdr end)))
(setf (cdr end) nil)
(unwind-protect (push (funcall function tail) ret)
(setf (cdr end) next)))
(push (funcall function tail) ret))))
All the answers are practical and can be used, but I believe none replicates exactly the Ruby's behavior:
> 1.upto(7).each_slice(3) { |x, y, z| p [x, y, z] }
[1, 2, 3]
[4, 5, 6]
[7, nil, nil]
To emulate Ruby, I believe the proper code is something similar to:
CL-USER> (defun each-slice (n list thunk)
(apply thunk (loop for i below n collect (nth i list)))
(if (> (length list) n)
(each-slice n (subseq list n) thunk)))
Generates a similar response when called:
CL-USER> (each-slice 3 '(1 2 3 4 5 6 7) (lambda (x y z) (print (list x y z))))
(1 2 3)
(4 5 6)
(7 NIL NIL)
NIL