Remove-adjacent-duplicates - scheme

I want to implement a function which takes a list as input and returns as value the same list with any sequence of repeated elements reduced to a single element:
Example:
(remove-adjacent-duplicates ’(y a b b a d a b b a d o o)) ; the return'(y a b a d a b a d o)
(remove-adjacent-duplicates ’(yeah yeah yeah)) ;the return '(yeah)
I have managed to do this with the following code:
(define (remove-adjacent-duplicates ls)
(if (null? ls)
'()
(let ((first (car ls)))
(let loop ((known first)
(rest (cdr ls))
(so-far (list first)))
(if (null? rest)
(reverse so-far)
(let ((first-remaining (car rest)))
(loop first-remaining
(cdr rest)
(if (equal? known first-remaining)
so-far
(cons first-remaining so-far)))))))))
But the code is not pretty and contains loop I want a recursion code using utilities such as 'car' 'cdr' and 'cons'.

loop is the name of an inner procedure and is called recursively; look up named lets. You can name it what you want; in my example I have called it iter to avoid this confusion.
You can also simplify a little:
(define (remove-adjacent-duplicates lst)
(let iter ((lst lst) (res '()))
(if (null? lst)
(reverse res)
(let ((next (car lst)))
(iter (cdr lst)
(if (or (null? res) (not (equal? next (car res))))
(cons next res)
res))))))

Related

Inserting word beside another word starting from the end of list

I have code which is inserting new word on the right side of choosen word
(define insertR
(lambda (new old lst)
(cond
((null? lst) (lst))
(else (cond
((eq? (car lst) old)
(cons old
(cons new (cdr lst))))
(else (cons (car lst)
(insertR new old
(cdr lst)))))))))
i need to make it insert that word beside first appearance of word starting from the end of list. Tried to work with reverse but could not get that to work.
There are two strategies you can take to add it next to the last occurence.
The first is to use a helper and start off with the reverse list. This is very simple and my preferred solution.
(define (insert-by-last-match insert find lst)
(let loop ((lst (reverse lst)) (acc '()))
(if (null? lst)
acc
(let ((a (car lst)))
(if (equal? a find)
(append (reverse (cdr lst))
(list* find insert acc))
(loop (cdr lst) (cons a acc)))))))
The other one is kind of obscure. Whenever you find the element you replace last-match with a callback that replaces the computation since it was made and until it gets called with the replacement and the rest of the list, which of course is the correct result. The work done until the end of the list is simply discarded since it is not used, but we do it since we are not sure if we are going to find a later one and then all the work uptil that is of course included in the result.
(define (insert-by-last-match insert find lst)
(define (helper lst last-match)
(if (null? lst)
(last-match)
(let* ((a (car lst)) (d (cdr lst)))
(cons a
(if (equal? a find)
(let/cc k
(helper d (lambda () (k (cons insert d)))))
(helper d last-match))))))
(helper lst (lambda () lst)))
call/cc (or its variant let/cc) is often described as time travel or advanced goto. It is not very intuitive. Here is a CPS version:
(define (insert-by-last-match insert find lst)
(define (helper lst last-match k)
(if (null? lst)
(last-match)
(let* ((a (car lst)) (d (cdr lst)) (k2 (lambda (v) (k (cons a v)))))
(if (equal? a find)
(helper d (lambda () (k2 (cons insert d))) k2)
(helper d last-match k2)))))
(helper lst (lambda () lst) (lambda (v) v)))
Basically this is the same as the previous only that here I have written the CPS code and with the let/cc version the implementation does it for me and I get to use k exactly where I need it. In this version you see there is no magic or time travel but the execution that should happen later is simply replaced at a point.
Write in a similar way insertL and apply it to the reversed list.
And reverse the result. Then you will have an insertion beside first appearance of word starting from the end of list
(define insertL
(lambda (new old lst)
(cond ((null? lst) '())
((eq? (car lst) old) (cons new lst))
(else (cons (car lst) (insertL new old (cdr lst)))))))
(define last-insertR
(lambda (new old lst)
(let* ((rlst (reverse lst))
(result (insertL new old rlst)))
(reverse result))))
test:
(last-insertR 'aa 'a '(b c d a h i a g))
;; '(b c d a h i a aa g)
By the way, the beauty of cond is that you can put the conditions always at the beginning - listed one under the other.
So one can write your insertR nicer as:
(define insertR
(lambda (new old lst)
(cond ((null? lst) '())
((eq? (car lst) old) (cons old (cons new (cdr lst))))
(else (cons (car lst) (insertR new old (cdr lst)))))))

recursion over list of characters in scheme

I have found a recursive problem in one page that says the following:
If a person enter a string with two consecutive letters that are the same, it should put a 5 between them. For example if I enter "hello"
it should print "hel5lo"
I have done the following program in Scheme:
(define (function listT)
(if (empty? listT)
'()
(begin
(if (eq? (car listT) (car (cdr listT)))
(display 5)
(display (car listT))
)))
(function (cdr listT)))
and tested with:
(function'( 'h 'e 'l 'l 'o))
and the problem I got is
car: contract violation
expected: pair?
given: ()
I suppose that is because at one moment (car (cdr listT)) will face an empty list, have tried with a conditional before, but still with some issues.
Is it possible to do it only using recursion over the list of characters with cdr and car? I mean not with new variables, strings, using reverse or loops?
Any help?
Thanks
This happens when there is only one character left in the list; (cdr listT) will be the empty list '() and the car of the empty list is undefined.
So you either need to check that the cdr isn't empty, for example:
(define (f str)
(let loop ((lst (string->list str)) (res '()))
(if (null? lst)
(list->string (reverse res))
(let ((c (car lst)))
(loop (cdr lst)
(cons c
(if (and (not (null? res)) (char=? c (car res)))
(cons #\5 res)
res)))))))
or, instead of looking one character ahead, turn around your logic and keep track of the last character, which is initialised to some value that will be different in every case (not as elegant as the first solution though IMO):
(define (f str)
(list->string
(let loop ((prev #f) (lst (string->list str)))
(if (null? lst)
'()
(let ((c (car lst)))
(if (equal? c prev)
(cons #\5 (cons c (loop c (cdr lst))))
(cons c (loop c (cdr lst)))))))))
[EDIT alternatively, with an explicit inner procedure:
(define (f str)
(define (inner prev lst)
(if (null? lst)
'()
(let ((c (car lst)))
(if (equal? c prev)
(cons #\5 (cons c (inner c (cdr lst))))
(cons c (inner c (cdr lst)))))))
(list->string (inner #f (string->list str))))
]
Testing:
> (f "hello")
"hel5lo"
> (f "helo")
"helo"
> (f "heloo")
"helo5o"
Side note: don't double quote:
> '('h 'e 'l 'l 'o)
'('h 'e 'l 'l 'o)
> (car '('h 'e 'l 'l 'o))
''h
This is probably not what you expected. Instead:
> '(h e l l o)
'(h e l l o)
> (car '(h e l l o))
'h
or
> (list 'h 'e 'l 'l 'o)
'(h e l l o)
> (car (list 'h 'e 'l 'l 'o))
'h
Also note that these are symbols, whereas, since you start from a string, you want characters:
> (string->list "hello")
'(#\h #\e #\l #\l #\o)
EDIT 2
I see you are still struggling with my answer. Here's a solution that should be as minimal as you requested, I hope this is it:
(define (f lst (prev #f))
(unless (null? lst)
(when (equal? (car lst) prev) (display "5"))
(display (car lst))
(f (cdr lst) (car lst))))
or even
(define (f lst)
(unless (null? lst)
(display (car lst))
(when (and (not (null? (cdr lst))) (equal? (car lst) (cadr lst)))
(display "5"))
(f (cdr lst))))
Testing:
> (f '(h e l l o))
hel5lo
> (f '(h e l o))
helo
> (f '(h e l o o))
helo5o
I have found a solution:
(define (func lisT)
(if (empty? (cdr lisT))
(display (car lisT))
(begin
(if (eq? (car lisT) (car (cdr lisT)))
(begin
(display (car lisT))
(display 5)
)
(display (car lisT))
)
(func (cdr lisT))
)
))
Here's a solution including just one, top-level recursive function:
(define (insert list item)
(if (< (length list) 2) ;; not enough elements to compare?
list ;; then just return the input
(let ((first (car list)) ;; capture the first element,
(second (cadr list)) ;; the second element,
(rest (insert (cdr list) item))) ;; and the recursively processed tail
(cons first ;; construct a list with the first element
(if (eq? first second) ;; compare the first two and return either
(cons item rest) ;; the item before the rest
rest))))) ;; or just the rest
It takes as input a list and an item to be inserted between each two consecutive identical elements. It does not display anything, but rather returns another list with the result of the insertion. For example,
(insert '(1 2 2 3 3 3 2 2 1) 0)
results in
(1 2 0 2 3 0 3 0 3 2 0 2 1)
This hopefully solves your problem and seeds further experimentation.
Here is a straightforward function from a list to a list:
(define (add5s s)
(cond ((null? s) s)
((null? (cdr s)) s)
((equal? (car s) (cadr s)) (cons (car s) (cons 5 (add5s (cdr s)))))
(else (cons (car s) (add5s (cdr s))))
)
)
A list either:
is null
has one element
begins with two equal elements
begins with two unequal elements
A list with a 5 put between consecutive equal elements is respectively:
the list
the list
the first element followed by a 5 followed by the rest of it with a 5 put between consecutive equal elements
the first element followed by the rest of it with a 5 put between consecutive equal elements
A Scheme string is not a list of characters or a list of symbols. If you want to input and output strings then you should use the corresponding string operators. Or write a function that defines this one, calls it with string->list of an input string and outputs list->string of this one's result list. Or a function like this one but that branches on string->list of its input string and outputs list->string of what this one returns.
(It is really not clear what code is to be written. You say "enters a string", but your "tested" code is a function that takes a list as argument, rather than reading from a port. And you say "put a 5" but you print argument list elements or a 5 via display to a port, rather than returning a value of the type of the argument. And you give an example passing an argument that is a list of quoted symbols rather than just symbols let alone characters. (If you want to pass a list of symbols then use '(h e l l o) or (list 'h 'e 'l 'l 'o).) Say exactly what is to be produced, eg, a function with what arguments, return value and effect on ports.)

Deep-reverse for trees in Scheme (Lisp)

I have a deep reverse for a basic tree data structure in Scheme
(define (deep-reverse t)
(cond ((null? t) '())
((not (pair? t)) t)
(else (cons (deep-reverse (cdr t)) (deep-reverse (car t))))))
(define stree (cons (list 1 2) (list 3 4)))
1 ]=> (deep-reverse stree)
;Value: (((() . 4) . 3) (() . 2) . 1)
I feel like a cleaner, better result would be:
(4 3 (2 1))
Can anyone provide some guidance as to where I'm going wrong in my deep-reverse function? Thank you.
It's better to split the task into simple operations instead of trying to do all at once. What you want to achieve can be described like this: Reverse the current list itself, then deep-reverse all sublists in it (or the other way round, the order of the two steps doesn't really matter. I choose this order because it results in nicer formatting of the source code).
Now, there already is a function in the standard library for simply reversing a list, reverse. So all you need to do is to combine that with the recursion on those elements that are sublists:
(define (deep-reverse t)
(map (lambda (x)
(if (list? x)
(deep-reverse x)
x))
(reverse t)))
Try this:
(define (deep-reverse t)
(let loop ((t t)
(acc '()))
(cond ((null? t) acc)
((not (pair? t)) t)
(else (loop (cdr t)
(cons (loop (car t) '()) acc))))))
Call it like this:
(define stree (cons (list 1 2) (list 3 4)))
(deep-reverse stree)
> (4 3 (2 1))
For creating a reversed list, one technique is to accumulate the answer in a parameter (I usually call it acc). Since we're operating on a list of lists, the recursion has to be called on both the car and the cdr part of the list. Lastly, I'm using a named let as a shorthand for avoiding the creation of an extra function, but the same result could be obtained by defining a helper function with two parameters, the tree and the accumulator:
(define (deep-reverse t)
(aux t '()))
(define (aux t acc)
(cond ((null? t) acc)
((not (pair? t)) t)
(else (aux (cdr t)
(cons (aux (car t) '()) acc)))))
I think it better to reverse a list based on its element count:
an empty list is reverse, a single element list is also reverted, more than 1 element is concatenation of the reverse of tail and head.
(defun deep-reverse (tree)
(cond ((zerop (length tree)) nil)
((and (= 1 (length tree)) (atom (car tree))) tree)
((consp (car tree)) (append (deep-reverse (cdr tree))
(list (deep-reverse (car tree)))))
(t (append (deep-reverse (cdr tree)) (list (car tree))))))
The following worked for me:
(define (deep-reverse tree)
(define (deep-reverse-iter items acc)
(cond
((null? items) acc)
((not (pair? items)) items)
(else (deep-reverse-iter
(cdr items)
(cons (deep-reverse (car items)) acc)))))
(deep-reverse-iter tree ()))
(define x (list (list 1 2) (list 3 4 (list 5 6))))
(newline)
(display (deep-reverse x))
It prints (((6 5) 4 3) (2 1)) as expected and uses the minimum of standard library functions: pair? to check if the tree is a cons and null? to check for an empty tree/list.
This solution for trees is a generalization of the reverse function for lists:
(define (reverse items)
(define (reverse-iter items acc)
(cond
((null? items) acc)
((not (pair? items)) items)
(else (reverse-iter (cdr items) (cons (car items) acc)))))
(reverse-iter items ()))
the difference being that deep-reverse is also applied to car items

How to remove non-duplicate elements from a list in Scheme?

Given a list,
(define ll '(a a a b c c c d e e e e))
I want to remove all non-duplicate elements and leave only one copy of the duplicate one, i.e. after removing, the result would be
(a c e)
My algorithm is:
Traverse through the list, comparing current element with next element.
If they're equal, then cons the current element with the list of the next recursive call. For example,
(a a a b c)
Move from left to right, encounter a and a.
(cons a (remove-nondup (cddr lst)))
Otherwise, skip current and next element.
(remove-nondup (cddr lst))
The problem I'm having is
(define (remove-nondup lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-nondup (cdr lst)))
(remove-nondup (cddr lst)))
lst))
The problem that I'm having is if there are more than 3 consecutive elements, I have no way to keep track of the previous-previous one. So I wonder should I use another procedure to remove all duplicates? or I can just put them into one procedure?
So my alternative current solution was,
(define (remove-dup lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-dup (cddr lst)))
(cons (car lst) (remove-dup (cdr lst))))
lst))
(define (remove-nondup-helper lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-nondup-helper (cdr lst)))
(remove-nondup (cddr lst)))
lst))
; call the helper function and remove-dup
(define (remove-nondup lst)
(remove-dup (remove-nondup-helper lst)))
Here's my solution: first, grab bagify (any version will do). Then:
(define (remove-singletons lst)
(define (singleton? ass)
(< (cdr ass) 2))
(map car (remove singleton? (bagify lst))))
remove is from SRFI 1. If you're using Racket, run (require srfi/1) first. Or, use this simple definition:
(define remove #f) ; Only needed in Racket's REPL
(define (remove pred lst)
(cond ((null? lst) lst)
((pred (car lst)) (remove pred (cdr lst)))
(else (cons (car lst) (remove pred (cdr lst))))))
Here's a way that uses only standard library functions and only tail calls, though it performs linear searches to see if an item has already been seen or put in the result:
(define remove-nondup
(λ (ls)
(reverse
(let loop ([ls ls] [found '()] [acc '()])
(cond
[(null? ls)
acc]
[(memq (car ls) found)
(loop (cdr ls)
found
(if (memq (car ls) acc)
acc
(cons (car ls) acc)))]
[else
(loop (cdr ls)
(cons (car ls) found)
acc)])))))
(remove-nondup '(a a a b c c c d e e e e)) =>
(a c e)
(remove-nondup '(a a a b c c c d e e e e f a a f)) =>
(a c e f)
The loop is a "named let": a handy way to stick a helper procedure inside a procedure without a lot of syntactic clutter.
If you only want to shrink consecutive duplicates down to one item, and remove items only when they don't occur twice consecutively, then here's a way to "remember" the item two cells ago without searching for it, and using only tail calls:
(define remove-nonconsecdup
(λ (ls)
(reverse
(letrec (
[got1 (λ (ls prev acc)
(cond
[(null? ls)
acc]
[(eq? prev (car ls))
(got2 (cdr ls) (cons prev acc))]
[else
(got1 (cdr ls) (car ls) acc)]))]
[got2 (λ (ls acc)
(cond
[(null? ls)
acc]
[(eq? (car acc) (car ls))
(got2 (cdr ls) acc)]
[else
(got1 (cdr ls) (car ls) acc)]))])
(if (null? ls)
'()
(got1 (cdr ls) (car ls) '()))))))
(remove-nonconsecdup '(a a a b c c c d e e e e)) =>
(a c e)
(remove-nonconsecdup '(a a a b c c c d e e e e f a a f)) =>
(a c e a)
I don't like reversing lists, but calling reverse is easy. If the extra cons'ing done by reverse is a problem, you could do non-tail calls or stick the items at the end of the list, but that's harder to do efficiently (but easy with a non-standard library macro).

Removing null elements from the scheme list

(define filter-in
(lambda (predicate list)
(let((f
(lambda (l)
(filter-in-sexpr predicate l))))
(map f list))))
(define filter-in-aux
(lambda (pred lst)
(if (null? lst) '()
(cons (filter-in-sexpr pred (car lst))
(filter-in-aux pred (cdr lst))))))
(define filter-in-sexpr
(lambda (pred sexpr)
(if (equal? (pred sexpr) #t)
sexpr
'())))
Calling (filter-in number? ’(a 2 (1 3) b 7)) produces ( () 2 () () 7).
How I can skip null elements from the generated list to get final outcome of (2 7) ?
The problem is that you're mapping filter-in-sxpr over the list. You can either run another filter pass to remove the nulls, or use a modified filter-in-aux like this:
(define filter-in-aux
(lambda (pred lst)
(if (null? lst) '()
(let ((h (filter-in-sexpr pred (car lst)))
(t (filter-in-aux pred (cdr lst))))
(if (null? h) t
(cons h t))))))

Resources