how to delete third element in a list using scheme - scheme

This is what I want:
(delete-third1 '(3 7 5)) ==> (3 7)
(delete-third1 '(a b c d)) ==> (a b d)
so I did something like:
(define (delete-third1 LS ) (list(cdr LS)))
which returns
(delete-third1 '(3 7 5))
((7 5))
when it should be (3 7). What am I doing wrong?

Think about what cdr is doing. cdr says that "given a list, chop off the first value and return the rest of the list". So it's removing only the first value, then returning you the rest of that list (which is exactly what you are seeing). Since it returns a list, you don't need a list (cdr LS) there either.
What you want is something like this:
(define (delete-n l n)
(if (= n 0)
(cdr l)
(append (list (car l)) (delete-n (cdr l) (- n 1)))))
(define (delete-third l)
(delete-n l 2))
So how does this work? delete-n will delete the nth element of a list by keeping a running count of what element we are up to. If we're not up to the nth element, then add that element to the list. If we are, then skip that element and add the rest of the elements to our list.
Then we simply define delete-third as delete-n where it removes the 3rd element (which is element 2 when we start counting at 0).

The simplest way would be: cons the first element, the second element and the rest of the list starting from the fourth position. Because this looks like homework I'll only give you the general idea, so you can fill-in the blanks:
(define (delete-third1 lst)
(cons <???> ; first element of the list
(cons <???> ; second element of the list
<???>))) ; rest of the list starting from the fourth element
The above assumes that the list has at least three elements. If that's not always the case, validate first the size of the list and return an appropriate value for that case.
A couple more of hints: in Racket there's a direct procedure for accessing the first element of a list. And another for accessing the second element. Finally, you can always use a sequence of cdrs to reach the rest of the rest of the ... list (but even that can be written more compactly)
From a practical standpoint, and if this weren't a homework, you could implement this functionality easily in terms of other existing procedures, and even make it general enough to remove elements at any given position. For example, for removing the third element (and again assuming there are enough elements in the list):
(append (take lst 2) (drop lst 3))
Or as a general procedure for removing an element from a given 0-based index:
(define (remove-ref lst idx)
(append (take lst idx) (drop lst (add1 idx))))
Here's how we would remove the third element:
(remove-ref '(3 7 5) 2)
=> '(3 7)

This works:
(define (delete-third! l)
(unless (or (null? l)
(null? (cdr l))
(null? (cddr l)))
(set-cdr! (cdr l) (cdddr l)))
l)
if you want a version that does not modify the list:
(define (delete-third l)
(if (not (or (null? l)
(null? (cdr l))
(null? (cddr l))))
(cons (car l) (cons (cadr l) (cdddr l)))
l))
and if you want to do it for any nth element:
(define (list-take list k)
(assert (not (negative? k)))
(let taking ((l list) (n k) (r '()))
(if (or (zero? n) (null? l))
(reverse r)
(taking (cdr l) (- n 1) (cons (car l) r)))))
(define (delete-nth l n)
(assert (positive? n))
(append (list-take l (- n 1))
(if (> n (length l))
'()
(list-tail l n))))
(define (nth-deleter n)
(lambda (l) (delete-nth l n)))
(define delete-3rd (nth-deleter 3))

Related

Scheme - returning first n-elements of an array

I'm trying to write a function in Scheme that returns the first n elements in a list. I'm want to do that without loops, just with this basic structure below.
What I've tried is:
(define n-first
(lambda (lst n)
(if (or(empty? lst) (= n 0))
(list)
(append (car lst) (n-first (cdr lst) (- n 1))))))
But I'm getting an error:
append: contract violation
expected: list?
given: 'in
I've tried to debug it and it looks that the tail of the recursion crashes it, meaning, just after returning the empty list the program crashes.
When replacing "append" operator with "list" I get:
Input: (n-first '(the cat in the hat) 3)
Output:
'(the (cat (in ())))
But I want to get an appended list.
A list that looks like (1 2 3) i constructed like (1 . (2 . (3 . ()))) or if you're more familiar with cons (cons 1 (cons 2 (cons 3 '()))). Thus (list 1 2 3)) does exactly that under the hood. This is crucial information in order to be good at procedures that works on them. Notice that the first cons cannot be applied before the (cons 2 (cons 3 '())) is finished so a list is always created from end to beginning. Also a list is iterated from beginning to end.
So you want:
(define lst '(1 2 3 4 5))
(n-first lst 0) ; == '()
(n-first lst 1) ; == (cons (car lst) (n-first (- 1 1) (cdr lst)))
(n-first lst 2) ; == (cons (car lst) (n-first (- 2 1) (cdr lst)))
append works like this:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1)
(append (cdr lst1) lst2))))
append is O(n) time complexity so if you use that each iteration of n parts of a list then you get O(n^2). For small lists you won't notice it but even a medium sized lists of a hundred thousand elements you'll notice append uses about 50 times longer to complete than the cons one and for large lists you don't want to wait for the result since it grows exponentially.
try so
(define first-n
(lambda (l)
(lambda (n)
((lambda (s)
(s s l n (lambda (x) x)))
(lambda (s l n k)
(if (or (zero? n)
(null? l))
(k '())
(s s (cdr l) (- n 1)
(lambda (rest)
(k (cons (car l) rest))))))))))
(display ((first-n '(a b c d e f)) 4))
(display ((first-n '(a b)) 4))
In scheme you must compute mentally the types of each expression, as it does not have a type checker/ type inference included.

Nested List Issue in Lisp

So I have to write a method that takes in a list like (nested '(4 5 2 8)) and returns (4 (5 () 2) 8).
I figured I needed to write 3 supporting methods to accomplish this. The first gets the size of the list:
(define (sizeList L)
(if (null? L) 0
(+ 1 (sizeList (cdr L)))))
input : (sizeList '(1 2 3 4 5 6 7))
output: 7
The second drops elements from the list:
(define (drop n L)
(if (= (- n 1) 0) L
(drop (- n 1) (cdr L))))
input : (drop 5 '(1 2 3 4 5 6 7))
output: (5 6 7)
The third removes the last element of a list:
(define (remLast E)
(if (null? (cdr E)) '()
(cons (car E) (remLast (cdr E)))))
input : (remLast '(1 2 3 4 5 6 7))
output: (1 2 3 4 5 6)
For the nested method I think I need to do the car of the first element, then recurse with the drop, and then remove the last element but for the life of me I can't figure out how to do it or maybe Im just continually messing up the parenthesis? Any ideas?
Various recursive solutions are possible, but the problem is that the more intuitive ones have a very bad performance, since they have a cost that depends on the square of the size of the input list.
Consider for instance this simple solution:
; return a copy of list l without the last element
(define (butlast l)
(cond ((null? l) '())
((null? (cdr l)) '())
(else (cons (car l) (butlast (cdr l))))))
; return the last element of list l
(define (last l)
(cond ((null? l) '())
((null? (cdr l)) (car l))
(else (last (cdr l)))))
; nest a linear list
(define (nested l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (list (car l) (nested (butlast (cdr l))) (last l)))))
At each recursive call of nested, there is a call to butlast and a call to last: this means that for each element in the first half of the list we must scan twice the list, and this requires a number of operations of order O(n2).
Is it possible to find a recursive solution with a number of operations that grows only linearly with the size of the list? The answer is yes, and the key to this solution is to reverse the list, and work in parallel on both the list and its reverse, through an auxiliary function that gets one element from both the lists and recurs on their cdr, and using at the same time a counter to stop the processing when the first halves of both lists have been considered. Here is a possible implementation of this algorithm:
(define (nested l)
(define (aux l lr n)
(cond ((= n 0) '())
((= n 1) (list (car l)))
(else (list (car l) (aux (cdr l) (cdr lr) (- n 2)) (car lr)))))
(aux l (reverse l) (length l)))
Note that the parameter n starts from (length l) and is decreased by 2 at each recursion: this allows to manage both the cases of a list with an even or odd number of elements. reverse is the primitive function that reverses a list, but if you cannot use this primitive function you can implement it with a recursive algorithm in the following way:
(define (reverse l)
(define (aux first-list second-list)
(if (null? first-list)
second-list
(aux (cdr first-list) (cons (car first-list) second-list))))
(aux l '()))

How do you obtain the largest n elements of a list using Scheme?

I'm stuck on a homework question and could use any hints or suggestions. I need to find the n largest numbers in a list using Scheme. I am trying to do this by creating helper functions that are called by the main function. So far I have this:
(define (get_max_value L)
(if (null? L)
'()
(apply max L)
)
(define (biggest_nums L n)
(if (null? n)
'()
(cons (get_max_value L) (biggest_nums L (- n 1)))
)
)
When I type (biggest_num '(3 1 4 2 5) 3) at the command prompt drRacket just hangs and doesn't even return an error message. Where am I going wrong?
The simplest solution is to first sort the numbers in ascending order and then take the n first. This translates quite literally in Racket code:
(define (biggest_nums L n)
(take (sort L >) n))
It works as expected:
(biggest_nums '(3 1 4 2 5) 3)
=> '(5 4 3)
Two mains problems with your code:
L always stays the same. L doesn't decrease in size when you make the recursive call, so the max will always be the same number in every recursive call.
You don't ever check n to make sure it contains the correct amount of numbers before returning the answer.
To solve these two problems in the most trivial way possible, you can put a (< n 1) condition in the if, and use something like (cdr L) to make L decrease in size in each recursive call by removing an element each time.
(define (biggest-nums n L)
(if (or (empty? L)
(< n 1))
'()
(cons (apply max L) (biggest-nums (- n 1) (cdr L)))))
So when we run it:
> (biggest-nums 3 '(1 59 2 10 33 4 5))
What should the output be?
'(59 33 10)
What is the actual output?
'(59 59 33)
OK, so we got your code running, but there are still some issues with it. Do you know why that's happening? Can you step through the code to figure out what you could do to fix it?
Just sort the list and then return the first n elements.
However, if the list is very long and n is not very large, then you probably don't want to sort the whole list first. In that case, I would suggest something like this:
(define insert-sorted
(lambda (item lst)
(cond ((null? lst)
(list item))
((<= item (car lst))
(cons item lst))
(else
(cons (car lst) (insert-sorted item (cdr lst)))))))
(define largest-n
(lambda (count lst)
(if (<= (length lst) count)
lst
(let loop ((todo (cdr lst))
(result (list (car lst))))
(if (null? todo)
result
(let* ((item (car todo))
(new-result
(if (< (car result) item)
(let ((new-result (insert-sorted item result)))
(if (< count (length new-result))
(cdr new-result)
new-result))
result)))
(loop (cdr todo)
new-result)))))))

Scheme append procedure

I'm having trouble appending a list to another list. Below is my code. When I run (append '(1 2) '(3 4)) I get '(1 3 2 4).
I want the output to be '(1 2 3 4)
(define (append l m)
(if (null? l) '()
(cons (car l) (append m (cdr l)))))
Thanks
Well by switching the two lists around like that (switching the position of m and l when calling append recursively), you'll get the first item of the first list followed by the first item of the second list etc.
If you don't want that, you should keep l as the first argument and m as the second. So you get:
(define (append l m)
(if (null? l) '()
(cons (car l) (append (cdr l) m))))
Of course this doesn't work as wanted either, because now you only get the first list back and nothing is appended at all. What you need to do is, once the first list is fully appended (i.e. once l is empty), you need to return the second one as the tail, like this:
(define (append l m)
(if (null? l) m
(cons (car l) (append (cdr l) m))))
I came across this while studying myself. #sepp2k's answer is a fine piece of instruction guiding OP to correct their code to achieve a recursive definition of append. Here's an alternate definition of my-append using the higher-order function foldr:
(define (myappend xs ys)
(foldr cons ys xs))

Scheme looping through list

I am trying to write some code that will loop through a list and add like terms. I'm trying to cons the cdr of the input list to a null list and then just compare the car of the list to the car of the new list and traverse down the list but my code just isn't working. What am I doing wrong here?
(define loop-add
(lambda (l temp outputList)
(if (or (equal? (cdr l) '()) (equal? (pair? (car l)) #f))
outputList
(if (equal? l '())
outputList
(let ((temp (cdr l)))
(if (equal? temp '())
(loop-add (cdr l) outputList)
(if (equal? (cdr (car l)) (cdr (car temp)))
(loop-add l (cdr temp) (cons (append (cdr (car l)) (cdr (car (cdr l)))) outputList))
(loop-add l temp outputList))))))))
but the problem now is at the end line its just going to be an infinite loop. I need a way to recur with the input list but with temp being the cdr of the previous temp list.
Start by writing a procedure that can transform your input list into a new list of the unique terms in the original list, so
(get-unique-terms '((2 1) (3 4) (5 3) (2 4)))
(1 4 3) ; or something like that
Call this new list TERMS. Now for each element in TERMS you can search the original list for matching elements, and get a sum of the coefficients:
(define (collect-like-terms l)
(let ((terms (get-unique-terms l)))
;; For each element of TERMS,
;; Find all elements of L which have a matching term,
;; Sum the coefficients of those elements,
;; Make a record of the sum and the term a la L.
;; Collect the results into a list and return.
Here's a simple solution in Racket:
(define (loop-add l)
(define table
(for/fold ([h (hash)]) ([i l])
(dict-update h (cadr i) (lambda (v) (+ v (car i))) 0)))
(dict-map table (lambda (key val) (list val key))))
(loop-add '((2 1) (3 4) (5 3) (2 4)))

Resources