how to define last in scheme? - scheme

how can I write a function to take the last element of the list?

find the last of a list:
(define (last l)
(cond ((null? (cdr l)) (car l))
(else (last (cdr l)))))
use map to map last to a list:
(map last '((a b) (c d) (e f)))
==> (b d f)
so a new function:
(define (last-list l)
(map last l)
)
(last-list '((a b) (c d) (e f)))
==> (b d f)

May not be the most efficient, but certainly one of the simplest:
(define (last lst)
(car (reverse lst)))
Examples:
(last '(1 2 3 4)) => 4
(last '((a b) (b c) (d e))) => (d e)

The code you've written - to take the last element of a list - is correctly returning the last element of the list. You have a list of lists. There is an outer list
(x y z)
where
x = (a b)
y = (c d)
z = (e f)
So you're getting the last element of the list, z, which is (e f)
Did you want your last function to do something different? If you want it to return the last element of the last nested list, you need to change your base case. Right now you return the car. Instead, you want to check if the car is a list and then call your nested-last function on that.
Make sense?

Your last function is good, but you have to think about what you want to do with it now.
You have a list of lists, and you want to take the last of all those.
So recurse down your list applying it each time:
(define (answer lst)
(cond ((null? (cdr l)) null)
(else (cons (last (car l)) (answer (cdr lst))))

Yet another possibility:
(define (last thelist)
(if
(null? (cdr thelist)) (car thelist)
(last (cdr thelist))))
(define (all-last lists) (map last lists))
Edit: just saw that you don't know map, and want a solution without it:
(define (all-last lists)
(if
(null? lists) `()
(cons (last (car lists)) (all-last (cdr lists)))))
As far as getting an empty list goes, I'd guess you're trying to use this map-like front-end with your original definition of last, whereas it's intended to work with the definition of last I gave above. Try the following definitions:
(define (last thelist) (if
(null? (cdr thelist)) (car thelist)
(last (cdr thelist))))
(define (all-last lists) (if
(null? lists) `()
(cons (last (car lists)) (all-last (cdr lists)))))
and running a quick test:
(all-last `((a b) (c d) (e f)))
The result should be:
(b d f)

(define last
(lambda (ls)
(list-ref ls (- (length ls) 1))))

I like short, sweet, fast, tail-recursive procedures.
Named let is my friend.
This solves the original problem and returns #f if the list has no last element.
(define (last L) (let f ((last #f) (L L)) (if (empty? L) last (f (car L) (cdr L)))))

The best way to get what you want:
(define (last lst)
(cond [(empty? lst) empty]
[(empty? (rest lst)) (first lst)]
[else (last (rest lst))]))

Related

Remove-adjacent-duplicates

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))))))

Remove all duplicates from a list in scheme [duplicate]

This question already has an answer here:
Removing all duplicate members from a list in scheme
(1 answer)
Closed 4 years ago.
Write a SCHEME function remove-duplicates that removes all duplicates from a list. (Hint: you might start by defining a function which removes all duplicates of a particular given value v from a list; then what?)
Example:
(remove-duplicates ’(1 2 3 4 5 3 1)) should produce
’(1 2 3 4 5)
I have this so far:
(define (remove v l)
(if (null? l)
l
(if (equal? v (car l))
(cdr l)
(cons (car l)
(remove v (cdr l))))))
(define (remove-duplicates l)
(cond ((null? l) '())
((null? (cdr l)) l)
((equal? (car l) (car (cdr l)))
(remove (cdr (cdr l)) (remove-duplicates (cdr (cdr l)))))
(else (cons (car l) (remove-duplicates (cdr l))))))
The whole point of abstraction is that you can have simpler code that does some of the job which is testable. Have you tested remove on its own?
(remove 'a '(g a b c a b c a))
; ==> (g b c a b c a)
So when it find one match the rest of the list is (cdr l). Are you just expecting one duplicate? This is the most important part of your solution.
When it comes to remove-duplicates you do too much. When the list is not empty the first element is the first element of the result consed with the recursion with the argument being the rest of argument with the first element removed. ie. (cons (car l) (remove-duplicates (remove (car l) (cdr l)). No more comparing necessary.

Scheme - n-ary subtraction function issues

I have the following n-ary function I defined:
(define (- . l)
(cond ((null? l) 0)
(else (b- (car l) (apply - (cdr l))))))
It works fine for two arguments, but anymore and it starts to add numbers in a strange way and I don't understand why.
Alternatively, I have a check implemented in a different version of this function in case there is only one argument:
(define (- . l)
(cond ((null? (cdr l)) (b- (b* l 2) l))
(else (b- (car l) (apply - (cdr l))))))
This second one does not work at all when I change the first condition.
Input should be something like (- 10 6 1)
I assume that b- is a binary subtraction, and that you want to mimic the usual subtraction of Scheme, which is a function such that:
with no arguments, gives an error,
with an argument, changes the sign of the argument,
with more than one argument, substracts from the first one all the others.
Here is a possibile solution (note that I've called the function n-):
(define (n- . l)
(define (aux l dec)
(if (null? l)
dec
(aux (cdr l) (b- dec (car l)))))
(cond ((null? l) (println "Error"))
((null? (cdr l)) (b- 0 (car l)))
(else (aux (cdr l) (car l)))))
(n-) ; => Error
(n- 3) ; => -3
(n- 10 6 1) ; => 3
(n- 11 4 8 2) ; => -3
The auxiliary function subtracts all the numbers from the list first argument to its second argument, and it is defined as a tail recursive function, so that it can be implemented in an iterative way.
The sane way to implement - is by using case-lambda, so that the unary, binary, and variadic cases can be handled separately:
(define -
(case-lambda
((a) (b- 0 a))
((a b) (b- a b))
((a b . rest) (apply - (b- a b) rest))))
Now, if you don't have case-lambda, then you'll have more work to do:
(define (- a . rest)
(if (null? rest)
(b- 0 a)
(let loop ((result a)
(rest rest))
(if (null? rest)
result
(loop (b- result (car rest)) (cdr rest))))))
This special-cases unary invocation to negate; otherwise, it iterates, using the first argument as the initial result, and updates the result by subtraction each time.

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.)

Flatten once procedure

I'm having a bit of a struggle with coding a procedure that flattens a list once, i.e
(flatten-once '((b) (c f) ((d)(e)))) would produce '(b c f (d) (e))). I checked up on a few sources on how the standard flatten procedure works but it implements functions that are not included in the intermediate student with lambda language form I'm required to use. As far as I have it figured out a foldr would be somewhat helpful and have managed to get this
(define (flatten-once lst)
(cond
[(empty? lst) lst]
[else
((foldr cons (first (rest lst)) (first lst)))]))
which returns '(b c f) , so I guess it flattens part of the list. I tried continuing the definition through recursion but that just gives errors, so I guess I'm missing something.
The proposed code is overly complicated, resist the temptation to use folds everywhere, they're not the answer to everything - I say this because I've seen other of your questions and frequently, there's an unnecessary call to foldr or foldl. A simple append will do the trick:
(define (flatten-once lst)
(apply append lst))
It works as expected:
(flatten-once '((b) (c f) ((d)(e))))
=> '(b c f (d) (e))
If the input list contains elements which are not lists, then a bit more of work needs to be done. To be extra-careful, we can do this:
(define (flatten-once lst)
(apply append
(map (lambda (e) (if (cons? e) e (list e)))
lst)))
Now it'll work for inputs such as this one, noticing that the element a was added to the list. Another alternative would be to delete it from the list, if that makes more sense then replace (list e) with '() in the code above.
(flatten-once '(a (b) (c f) ((d)(e))))
=> '(a b c f (d) (e))
Finally, in the spirit of #Alex's answer, this second variant can also be written using foldr:
(define (flatten-once lst)
(foldr (lambda (e acc)
(append (if (cons? e) e (list e)) acc))
'()
lst))
The trick is as Óscar López already said, to use append.
If you want to use a solution with foldr :
(define (flatten-once lst)
(foldr append '() lst))
It should work as expected.
Less elegant that Oscar's version, but without append (and twice as fast in my tests):
(define (flatten-once lst)
(reverse
(let loop ((lst lst) (first #t) (res null))
(if (null? lst)
res
(let ((e (car lst)))
(loop (cdr lst)
first
(if (and first (cons? e))
(loop e #f res)
(cons e res))))))))
NB in intermediate student with lambda language this needs to be expressed as:
(define (flatten-once-helper lst first res)
(if (null? lst)
res
(let ((e (car lst)))
(flatten-once-helper
(cdr lst)
first
(if (and first (cons? e))
(flatten-once-helper e #f res)
(cons e res))))))
(define (flatten-once lst)
(reverse (flatten-once-helper lst #t null)))

Resources