zip function in Racket/Scheme - recursion

Given two lists, return a list whose elements are lists of size two, such that for the i-th list, the first element is the i-th element of the first original list, and the second element is the i-th element of the second original list. If one list is smaller than the other, the resulting list is of the smallest size; and so if one of the lists is empty, return an empty list. For example:
> (zip '(1 2) '(3 4))
'((1 3) (2 4))
> (zip '(1 2 3) '())
'()
> (zip '() '(4 5 6))
'()
> (zip '(8 9) '(3 2 1 4))
'((8 3) (9 2))
> (zip '(8 9 1 2) '(3 4))
'((8 3) (9 4))

Try so:
(map cons '(1 2 3) '(a b c))
or so:
(map list '(1 2 3) '(a b c))
(define zip (lambda (l1 l2) (map list l1 l2)))
->(zip '(1 2 3) '(x y z))
'((1 x) (2 y) (3 z))

Because you didn't post the code you've written, I'm guessing this is homework. I'll give you some hints to get started, this is the general structure of the solution, fill-in the blanks - it'll be much more fun if you reach the correct answer by your own means!
(define (zip lst1 lst2)
(cond ((<???> lst1) ; if the first list is empty
<???>) ; then return the empty list
((<???> lst2) ; if the second list is empty
<???>) ; then also return the empty list
(else ; otherwise
(cons (list ; cons a list with two elements:
<???> ; the first from the first list
<???>) ; and the first from the second list
(zip <???> <???>))))) ; advance recursion over both lists
I tested the above implementation with the sample inputs, and the results are as expected:
(zip '(1 2) '(3 4))
=> '((1 3) (2 4))
(zip '(1 2 3) '())
=> '()
(zip '() '(4 5 6))
=> '()
(zip '(8 9) '(3 2 1 4))
=> '((8 3) (9 2))
(zip '(8 9 1 2) '(3 4))
=> '((8 3) (9 4))

If you've solved the problem for the first element then you can recurse on the rest of the list:
(define (zip l1 l2)
(if (or (null? l1) (null? l2))
'()
(cons (list (car l1) (car l2))
(zip (cdr l1) (cdr l2)))))
provided you handle the base case where either list is empty.
> (zip '(1 2 3 4) '(a b))
((1 a) (2 b))
> (zip '() '(a b))
()

If we accept Racket functions, and also relax the requirement of returning 2-tuples in favor of a more general zip, then I would check out for/list. Here are examples zipping or interleaving two or three lists, stopping at the shortest list.
(define l1 '(a b c))
(define l2 '(1 2 3))
(define l3 '(true false))
;; → '((a 1 true) (b 2 false))
(for/list ([i l1] [j l2] [k l3])
(list i j k))
;; → '((a 1) (b 2) (c 3))
(for/list ([i l1] [j l2])
(list i j))
;; → '()
(for/list ([i l1] [j l2] [k null])
(list i j k))

If your map implementation stops at the shortest list, then zip can be defined with map, Scheme's list procedure and apply. Here's a hint:
(define (zip . lsts)
(apply <??> <??> lsts))
SRFI-1's map is sufficient. So in Racket you add (require (only-in srfi/1 map))

Today, I came across the same exercise and did my own implementation which is different from all the ones people posted here. All the other answers are great. I really liked the most voted one from #Alinsoar.
Definitely, the other answers are actually better than my implementation. But I will post it anyway. Maybe, this can help someone trying to learn Racket.
(define (shorter-list xs ys)
(if (> (length xs) (length ys))
ys
xs))
(define (zip xs ys)
(cond [(null? (shorter-list xs ys)) null]
[true (cons (list (car xs) (car ys)) (zip (cdr xs) (cdr ys)))]))

Related

Common Lisp calling a deftype method

I'm not been able to make this working on. I'm defining a predicate using deftype SameType(x y) method, which evaluates whether the elements of list x and list y are of the same type, and in the same position. The problem comes when I try to call the predicate for testing. I receive an error ERROR: SameType is undefined This is my code:
(deftype SameType (x y)
`(cond
((and (null x) (null y) T))
(
(and (numberp (car x)) (numberp (car y)))
(SameType (cdr x) (cdr y) )
)
(
(and (stringp (car x)) (stringp (car y)))
(SameType (cdr x) (cdr y) )
)
(
(and (atom (car x)) (atom (car y)))
(SameType (cdr x) (cdr y) )
)
(T nil)
)
)
And this is how I'm calling it
(SameType '(A B C 1 2 4 A) '('() G 2 5 6 A B))
I already checked on various onine resources, even related questions on this site.
deftype can be used to define a type, not a predicate. For instance, to define the type of the lists with only integers, you could write something like:
(defun intlistp (l)
"predicate to check if l is a list consisting only of integers"
(and (listp l) ; l is a list and
(every #'integerp l))) ; every element of l is an integer
(deftype integer-list ()
"the type of list of integers"
`(satisfies intlistp))
and then you can check if a value satisfies this type:
CL-USER> (typep '(1 2 3) 'integer-list)
T
CL-USER> (typep '(1 2.5 3) 'integer-list)
NIL
If you want to check if two lists have the same type according to your definition, then you could define a regular function:
(defun same-type (l1 l2)
"check if lists l1 and l2 have the same length and corresponding
elements of the same CL type"
(cond ((null l1) ; if l1 is null
(null l2)) ; returns true only if also l2 is null
((and (consp l1) ; if l1 is a cons
(consp l2) ; and l2 is a cons too,
(typep (car l1) (type-of (car l2)))) ; and their cars have the same CL type
(same-type (cdr l1) (cdr l2))))) ; go recursively on their cdrs
CL-USER> (same-type '(1 a 3) '(2 b 4))
T
CL-USER> (same-type '(1 "a" 3) '(2 "b" 3))
T
CL-USER> (same-type '(1 a 3) '(2 b 4.5))
NIL
CL-USER> (same-type '(1 a 3) '(2 b 4 3))
NIL
CL-USER> (same-type '(1 2 (3 4)) '(1 6 (4 5)))
T
CL-USER> (same-type '(1 2 (3 4)) '(1 6 (4 5 6)))
T
Note that, as you can see from the last example, the type is checked only for the first level of the list.

Lisp - Split Recursive

I was trying to make a recursive function to split a list into two lists according the number of elements one wants.
Ex:
(split 3 '(1 3 5 7 9)) ((1 3 5) (7 9))
(split 7 '(1 3 5 7 9)) ((1 3 5 7 9) NIL)
(split 0 '(1 3 5 7 9)) (NIL (1 3 5 7 9))
My code is like this:
(defun split (e L)
(cond ((eql e 0) '(() L))
((> e 0) (cons (car L) (car (split (- e 1) (cdr L))))))))
I don't find a way to join the first list elements and return the second list.
Tail recursive solution
(defun split (n l &optional (acc-l '()))
(cond ((null l) (list (reverse acc-l) ()))
((>= 0 n) (list (reverse acc-l) l))
(t (split (1- n) (cdr l) (cons (car l) acc-l)))))
Improved version
(in this version, it is ensured that acc-l is at the beginning '()):
(defun split (n l)
(labels ((inner-split (n l &optional (acc-l '()))
(cond ((null l) (list (reverse acc-l) ()))
((= 0 n) (list (reverse acc-l) l))
(t (inner-split (1- n) (cdr l) (cons (car l) acc-l))))))
(inner-split n l)))
Test it:
(split 3 '(1 2 3 4 5 6 7))
;; returns: ((1 2 3) (4 5 6 7))
(split 0 '(1 2 3 4 5 6 7))
;; returns: (NIL (1 2 3 4 5 6 7))
(split 7 '(1 2 3 4 5 6 7))
;; returns ((1 2 3 4 5 6 7) NIL)
(split 9 '(1 2 3 4 5 6 7))
;; returns ((1 2 3 4 5 6 7) NIL)
(split -3 '(1 2 3 4 5 6 7))
;; returns (NIL (1 2 3 4 5 6 7))
In the improved version, the recursive function is placed one level deeper (kind of encapsulation) by using labels (kind of let which allows definition of local functions but in a way that they are allowed to call themselves - so it allows recursive local functions).
How I came to the solution:
Somehow it is clear, that the first list in the result must result from consing one element after another from the beginning of l in successive order. However, consing adds an element to an existing list at its beginning and not its end.
So, successively consing the car of the list will lead to a reversed order.
Thus, it is clear that in the last step, when the first list is returned, it hast to be reversed. The second list is simply (cdr l) of the last step so can be added to the result in the last step, when the result is returned.
So I thought, it is good to accumulate the first list into (acc-l) - the accumulator is mostly the last element in the argument list of tail-recursive functions, the components of the first list. I called it acc-l - accumulator-list.
When writing a recursive function, one begins the cond part with the trivial cases. If the inputs are a number and a list, the most trivial cases - and the last steps of the recursion, are the cases, when
the list is empty (equal l '()) ---> (null l)
and the number is zero ----> (= n 0) - actually (zerop n). But later I changed it to (>= n 0) to catch also the cases that a negative number is given as input.
(Thus very often recursive cond parts have null or zerop in their conditions.)
When the list l is empty, then the two lists have to be returned - while the second list is an empty list and the first list is - unintuitively - the reversed acc-l.
You have to build them with (list ) since the list arguments get evaluated shortly before return (in contrast to quote = '(...) where the result cannot be evaluated to sth in the last step.)
When n is zero (and later: when n is negative) then nothing is to do than to return l as the second list and what have been accumulated for the first list until now - but in reverse order.
In all other cases (t ...), the car of the list l is consed to the list which was accumulated until now (for the first list): (cons (car l) acc-l) and this I give as the accumulator list (acc-l) to split and the rest of the list as the new list in this call (cdr l) and (1- n). This decrementation in the recursive call is very typical for recursive function definitions.
By that, we have covered all possibilities for one step in the recursion.
And that makes recursion so powerful: conquer all possibilities in ONE step - and then you have defined how to handle nearly infinitely many cases.
Non-tail-recursive solution
(inspired by Dan Robertson's solution - Thank you Dan! Especially his solution with destructuring-bind I liked.)
(defun split (n l)
(cond ((null l) (list '() '()))
((>= 0 n) (list '() l))
(t (destructuring-bind (left right) (split (1- n) (cdr l))
(list (cons (car l) left) right)))))
And a solution with only very elementary functions (only null, list, >=, let, t, cons, car, cdr, cadr)
(defun split (n l)
(cond ((null l) (list '() '()))
((>= 0 n) (list '() l))
(t (let ((res (split (1- n) (cdr l))))
(let ((left-list (car res))
(right-list (cadr res)))
(list (cons (car l) left-list) right-list))))))
Remember: split returns a list of two lists.
(defun split (e L)
(cond ((eql e 0)
'(() L)) ; you want to call the function LIST
; so that the value of L is in the list,
; and not the symbol L itself
((> e 0)
; now you want to return a list of two lists.
; thus it probably is a good idea to call the function LIST
; the first sublist is made of the first element of L
; and the first sublist of the result of SPLIT
; the second sublist is made of the second sublist
; of the result of SPLIT
(cons (car L)
(car (split (- e 1)
(cdr L)))))))
Well let’s try to derive the recursion we should be doing.
(split 0 l) = (list () l)
So that’s our base case. Now we know
(split 1 (cons a b)) = (list (list a) b)
But we think a bit and we’re building up the first argument on the left and the way to build up lists that way is with CONS so we write down
(split 1 (cons a b)) = (list (cons a ()) b)
And then we think a bit and we think about what (split 0 l) is and we can write down for n>=1:
(split n+1 (cons a b)) = (list (cons a l1) l2) where (split n b) = (list l1 l2)
So let’s write that down in Lisp:
(defun split (n list)
(ecase (signum n)
(0 (list nil list))
(1 (if (cdr list)
(destructuring-bind (left right) (split (1- n) (cdr list))
(list (cons (car list) left) right))
(list nil nil)))))
The most idiomatic solution would be something like:
(defun split (n list)
(etypecase n
((eql 0) (list nil list))
(unsigned-integer
(loop repeat n for (x . r) on list
collect x into left
finally (return (list left r))))))

How to build a rolling window procedure using racket/scheme?

When written this way the error says: 4 parts after if:
(define (rolling-window l size)
(if (< (length l) size) l
(take l size) (rolling-window (cdr l) size)))
and when there's another paranthesis to make it 3 parts:
(define (rolling-window l size)
(if (< (length l) size) l
((take l size) (rolling-window (cdr l) size))))
then it says: application: not a procedure;
How to write more than one expression in if's else in racket/scheme?
Well that's not really the question. The question is "How to build a rolling window procedure using racket?". Anyway, it looks like you're probably coming from another programming language. Processing linked lists can be a little tricky at first. But remember, to compute the length of a list, you have to iterate through the entire list. So using length is a bit of an anti-pattern here.
Instead, I would recommend you create an auxiliary procedure inside your rolling-window procedure which builds up the window as you iterate thru the list. This way you don't have to waste iterations counting elements of a list.
Then if your aux procedure ever returns and empty window, you know you're done computing the windows for the given input list.
(define (rolling-window n xs)
(define (aux n xs)
(let aux-loop ([n n] [xs xs] [k identity])
(cond [(= n 0) (k empty)] ;; done building sublist, return sublist
[(empty? xs) empty] ;; reached end of xs before n = 0, return empty window
[else (aux-loop (sub1 n) (cdr xs) (λ (rest) (k (cons (car xs) rest))))]))) ;; continue building sublist
(let loop ([xs xs] [window (aux n xs)] [k identity])
(cond ([empty? window] (k empty)) ;; empty window, done
([empty? xs] (k empty)) ;; empty input list, done
(else (loop (cdr xs) (aux n (cdr xs)) (λ (rest) (k (cons window rest)))))))) ;; continue building sublists
(rolling-window 3 '(1 2 3 4 5 6))
;; => '((1 2 3) (2 3 4) (3 4 5) (4 5 6))
It works for empty windows
(rolling-window 0 '(1 2 3 4 5 6))
;; => '()
And empty lists too
(rolling-window 3 '())
;; => '()
Here is an alternative:
#lang racket
(define (rolling-window n xs)
(define v (list->vector xs))
(define m (vector-length v))
(for/list ([i (max 0 (- m n -1))])
(vector->list (vector-copy v i (+ i n)))))
(rolling-window 3 '(a b c d e f g))
(rolling-window 3 '())
(rolling-window 0 '(a b c))
Output:
'((a b c) (b c d) (c d e) (d e f) (e f g))
'()
'(() () () ()) ; lack of spec makes this ok !
Following modification of OP's function works. It includes an outlist for which the initial default is empty list. Sublists are added to this outlist till (length l) is less than size.
(define (rolling-window l size (ol '()))
(if (< (length l) size) (reverse ol)
(rolling-window (cdr l) size (cons (take l size) ol))))
Testing:
(rolling-window '(1 2 3 4 5 6) 2)
(rolling-window '(1 2 3 4 5 6) 3)
(rolling-window '(1 2 3 4 5 6) 4)
Output:
'((1 2) (2 3) (3 4) (4 5) (5 6))
'((1 2 3) (2 3 4) (3 4 5) (4 5 6))
'((1 2 3 4) (2 3 4 5) (3 4 5 6))
Any improvements on this one?
(define (rolling-window l size)
(cond ((eq? l '()) '())
((< (length l) size) '())
((cons (take l size) (rolling-window (cdr l) size)))))

An issue with common prefix list function

(define (long a b)
(cond ((null? a) '())
((null? b) '())
(else
(if (equal? (car a) (car b))
(cons a (long (cdr a) (cdr b)))
(cons b (long (cdr a) (cdr b)))))))
This function is suppose to the find the longest common prefix between 2 lists. So when I input '(1 2) and '(1 2 3), I should get '(1 2). However, when I run (long '(1 2) '(1 2 3)), I get ((1 2) (2)). When I retraced my steps through my code, I don't seem to find the issue. Can someone please help me find the issue?
Thank you.
A simple solution is the following:
(define (long a b)
(cond ((null? a) '())
((null? b) '())
((equal? (car a) (car b)) (cons (car a) (long (cdr a) (cdr b))))
(else '())))
When a list terminates the prefix is the empty list; if both the cars are equal, the result is the list with the car and the longest prefix of the cdrs of the lists. Otherwise, the lists differ for the first element, so the result is the empty list.
One can use 'for/list' loop with conditions here:
(define (long a b)
(for/list ((i a)
(j b)
#:break (not(= i j)))
i))
(long '(1 2 3) '(1 2))
Output:
'(1 2)

How can i remove parentheses in scheme?

i have a function in scheme, this function calls another function many times, and every time this function appends return value of another function to result value.
but finally i want to get a result such that '(a b c), however i get a result such that '((a) (b) (c)) how can i fix this problem? i have searched but i couldn't find good solution.
my little code like that not all of them.
(append res (func x))
(append res (func y))
(append res (func z))
my code like this
(define (check a )
'(1)
)
(define bos '())
(define (func a)
(let loop1([a a] [res '()])
(cond
[(eq? a '()) res]
[else (let ([ x (check (car a))])
(loop1 (cdr a) (append res (list x)))
)]
)
))
Try this:
(define (func a)
(let loop1 ([a a] [res '()])
(cond
[(eq? a '()) res]
[else
(let ([ x (check (car a))])
(loop1 (cdr a) (append res x)))])))
Notice that the only change I made (besides improving the formatting) was substituting (list x) with x. That will do the trick! Alternatively, but less portable - you can use append* instead of append:
(append* res (list x))
As a side comment, you should use (null? a) for testing if the list is empty. Now if we test the procedure using the sample code in the question, we'll get:
(func '(a b c))
=> '(1 1 1)
It seems that instead of
(loop1 (cdr a) (cdr b) c (append res (list x)))
you want
(loop1 (cdr a) (cdr b) c (append res x))
Basically the trick is to use cons instead of list. Imagine (list 1 2 3 4) which is the same as (cons 1 (cons 2 (cons 3 (cons 4 '())))). Do you see how each part is (cons this-iteration-element (recurse-further)) like this:
(define (make-list n)
(if (zero? n)
'()
(cons n (make-list (sub1 n)))))
(make-list 10) ; ==> (10 9 8 7 6 5 4 3 2 1)
Usually when you can choose direction you can always make it tail recursive with an accumulator:
(define (make-list n)
(let loop ((x 1) (acc '()))
(if (> x n)
acc
(loop (add1 x) (cons x acc))))) ; build up in reverse!
(make-list 10) ; ==> (10 9 8 7 6 5 4 3 2 1)
Now this is a generic answer. Applied to your working code:
(define (func a)
(let loop1 ([a a] [res '()])
(cond
[(eq? a '()) (reverse res)]
[else
(let ([x (check (car a))])
(loop1 (cdr a) (cons (car x) res)))])))
(func '(a b c)) ; ==> (1 1 1)
append replaces the cons so why not put the car og your result to the rest of the list. Since you want the result in order I reverse the result in the base case. (can't really tell from the result, but I guessed since you ise append)

Resources