How to delete the 2nd to last element from a list in Scheme? - scheme

I'm using Scheme and I'm trying to remove the 2nd to last element in the list recursively.
This is what I have:
(define delete
(lambda (num lst)
(cond
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete num (cdr lst)))))))
(define second
(lambda(lst)
(delete (- (length lst) 1) lst)))
(second '(1))
(second '(3 5 6))
(second '(2 7 8 4 9))
returns this:
()
(3 5)
(2 7 8 4)
When it should return this:
()
(3 6)
(2 7 8 9)
The (second '(1)) is doing what I intended but I've playing with the other part for a few hours and I'm still at a loss. Any tips or suggestions would be very appreciated at this point.
EDIT:
Wow, Thank you! It was that one line of missing code -_- Duh me!

You never use the num argument. So you will always iterate until the list has 1 element or is null. You could add a special case for when the list has 2 elements:
(define delete
(lambda (num lst)
(cond
((equal? (length lst) 2) (cdr lst))
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete num (cdr lst)))))))
(define second
(lambda(lst)
(delete (- (length lst) 1) lst)))
Since the num argument isn't used, you can do:
(define delete_second_last
(lambda (lst)
(cond
((equal? (length lst) 2) (cdr lst))
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete_second_last (cdr lst)))))))
(delete_second_last '(3 6 7 9 10))

Related

Deep recursion in Scheme

I have a problem with deep recursion in scheme
The output should be
(1 2 3 (4 5))
~> ((1) (2) (3) ((4) (5)))
But my output is (1 (2 (3 ((4 (5 ())) ())))).
It seems like the quote is at the wrong place
I got these
(define (DoublebubbleLst lst)
(cond ((null? lst) lst)
((not (pair? lst))
(append lst))
(else(list
(DoublebubbleLst (car lst))
(DoublebubbleLst (cdr lst))))))
And what's my problem
This seems to work:
(define (double-bubble-list lst)
(cond ((null? lst) lst)
((not (list? (car lst)))
(cons (list (car lst))
(double-bubble-list (cdr lst))))
(else (cons (double-bubble-list (car lst))
(double-bubble-list (cdr lst))))))
Example:
> (double-bubble-list '(1 2 3 (4 5)))
'((1) (2) (3) ((4) (5)))

Scheme: Iterate Through Whole List

I have a program that takes in an input like '((1 plus 2) (2 times 2)). However, when I run that example input, it only prints out '(3). How can I change this code to parse through the whole list that I give it and not just the first instance in the list?
(define math
(lambda (lst)
(cond [(null? lst) lst]
[(equal? (second (car lst)) 'plus) (cons (+ (first (car lst)) (third (car lst))) '())]
[(equal? (second (car lst)) 'times) (cons (* (first (car lst)) (third (car lst))) '())])
))
You need to advance the recursion, so the procedure will continue with the rest of the expressions in the list. Try this:
(define math
(lambda (lst)
(cond [(null? lst) lst]
[(equal? (second (car lst)) 'plus)
(cons (+ (first (car lst)) (third (car lst)))
(math (cdr lst)))] ; advance the recursion
[(equal? (second (car lst)) 'times)
(cons (* (first (car lst)) (third (car lst)))
(math (cdr lst)))]))) ; advance the recursion
It works as expected:
(math '((1 plus 2) (2 times 2)))
=> '(3 4)

Splitting a list recursively in Scheme

What I want to do is define a list such as (define lst '(1 2 3 4 5 6)) and then call (split lst) which will return '((1 3 5) (2 4 6)).
Some examples:
When lst is '(1 2 3 4 5 6) it should return '((1 3 5) (2 4 6))
When lst is '(1 2 3 4 5 6 7) it should return '((1 3 5 7) (2 4 6))
When lst is '("a" "little" "bit" "of" "that" "to" "spice" "things" "up") it should return '(("a" "bit" "that" "spice" "up") ("little" "of" "to" "things"))
It should alternate when building the two lists. So the first index should go in the first list, second index in the second list, third index in the first list, etc.
Here is my current script.
(define (split lst)
(cond ((null? lst) lst)
((null? (cdr lst)) lst)
((cons (cons (car lst) (split (cddr lst))) (cons (cadr lst) (split (cddr lst)))))))
Currently, this is what outputs when I split the list '(1 2 3 4 5 6)
((1 (3 (5) 6) 4 (5) 6) 2 (3 (5) 6) 4 (5) 6)
Lets fix your code step by step:
(define (split lst)
(cond ((null? lst) lst)
((null? (cdr lst)) lst)
((cons (cons (car lst) (split (cddr lst))) (cons (cadr lst) (split (cddr lst)))))))
The first thing I notice is the lack of an else in the last case of the cond. Conds are supposed to look like:
(cond (question-1 answer-1)
(question-2 answer-2)
...
(else else-answer))
With an else inserted your code looks like this:
(define (split lst)
(cond ((null? lst) lst)
((null? (cdr lst)) lst)
(else
(cons (cons (car lst) (split (cddr lst))) (cons (cadr lst) (split (cddr lst)))))))
The next thing is the first base case, or the answer to the (null? lst) cond question. On an empty list what should it return?
It seems like no matter how long the list is, it should always return a list of exactly two inner lists. So when lst is empty the logical answer would be (list '() '()).
(define (split lst)
(cond ((null? lst)
(list '() '()))
((null? (cdr lst)) lst)
(else
(cons (cons (car lst) (split (cddr lst))) (cons (cadr lst) (split (cddr lst)))))))
Next is the second base case, the answer to the (null? (cdr lst)) cond question. Again it should return a list of exactly two inner lists:
(list ??? ???)
The the first index should go in the first list, and then there's nothing to go in the second list.
(list (list (car lst)) '())
In the context of your code:
(define (split lst)
(cond ((null? lst)
(list '() '()))
((null? (cdr lst))
(list (list (car lst)) '()))
(else
(cons (cons (car lst) (split (cddr lst))) (cons (cadr lst) (split (cddr lst)))))))
Now, what is the behavior of this function?
> (split '(1 2 3 4 5 6))
'((1 (3 (5 () ()) 6 () ()) 4 (5 () ()) 6 () ()) 2 (3 (5 () ()) 6 () ()) 4 (5 () ()) 6 () ())
Still not what you want. So what is the last case, recursive case, supposed to do?
Consider what you're "given" and what you need to "produce".
Given:
(car lst) the first element
(cadr lst) the second element
(split (cddr lst)) a list of exactly two inner lists
You should produce:
(list ??? ???)
Where the first ??? hole contains the first element and the first of the two inner lists, and the second ??? hole contains the second element and the second of the two inner lists.
This suggests code like this:
(list (cons (car lst) (first (split (cddr lst))))
(cons (cadr lst) (second (split (cddr lst)))))
Or, since car gets the first and cadr gets the second:
(list (cons (car lst) (car (split (cddr lst))))
(cons (cadr lst) (cadr (split (cddr lst)))))
In the context of your code:
(define (split lst)
(cond ((null? lst)
(list '() '()))
((null? (cdr lst))
(list (list (car lst)) '()))
(else
(list (cons (car lst) (car (split (cddr lst))))
(cons (cadr lst) (cadr (split (cddr lst))))))))
Using it produces what you want:
> (split '(1 2 3 4 5 6))
'((1 3 5) (2 4 6))
> (split '(1 2 3 4 5 6 7))
'((1 3 5 7) (2 4 6))
> (split '("a" "little" "bit" "of" "that" "to" "spice" "things" "up"))
'(("a" "bit" "that" "spice" "up") ("little" "of" "to" "things"))
Now what was the difference between this and what you had before?
Your code before:
(cons (cons (car lst) (split (cddr lst)))
(cons (cadr lst) (split (cddr lst))))
The fixed version:
(list (cons (car lst) (car (split (cddr lst))))
(cons (cadr lst) (cadr (split (cddr lst)))))
The first difference is that your original version uses cons on the outside, while the fixed version uses list instead. This is because (list ??? ???) always returns a list of exactly two elements, while (cons ??? ???) can return a list of any size greater than 1, which has the first thing merged onto an existing second list. (list ??? ???) is what you want here because you specified that it should return a list of exactly two inner lists.
The second difference is in how you use the recursive call (split (cddr lst)).
This has to do with how you interpreted the "given" part of the recursive case. You had assumed that the first call to split would give you the first "inner" list, and the second call to split would give you the second "inner" list. In fact it gives you a list of both of those both times. So for the first one you have to get the "first" or car of it, and for the second one you have get the "second" or cadr of it.
Looks like this might be what you're looking for:
(define (split lst)
(define (loop lst do-odd odds evens)
(if (null? lst)
(list (reverse odds) (reverse evens))
(loop (cdr lst) (not do-odd)
(if do-odd (cons (car lst) odds) odds)
(if (not do-odd) (cons (car lst) evens) evens))))
(loop lst #t '() '()))
In use:
1 ]=> (split '(1 2 3 4 5 6))
;Value 2: ((1 3 5) (2 4 6))
1 ]=> (split '(1 2 3 4 5 6 7))
;Value 3: ((1 3 5 7) (2 4 6))
This uses the variable do-odd in the inner loop function (which is tail-recursive, by the way, so it is fast!) to figure out which list it should add the (car lst) to.
Downsides to this function: the call to reverse in the base case can be expensive if your lists are very long. This may or may not be a problem. Profiling your code will tell you if it's a bottleneck.
UPDATE: You can also use the function reverse!, which destructively modifies the array in question. I did some informal profiling, and it didn't seem to make that much of a difference speed-wise. You will have to test this under your specific circumstances.
Now, if this isn't intended to be performant, use whatever you want! :)
My shortest solution
(define (split l)
(cond ((null? l) '(() ()))
((null? (cdr l)) (list (list (car l)) '()))
(else (map cons (list (car l) (cadr l))
(split (cddr l))))))
Similar but wordier solution
Ensure that split always returns a list of two lists.
Then you can define it quite compactly:
(define (split l)
(cond ((null? l) '(() ()))
((null? (cdr l)) (list (list (car l)) '()))
(else (double-cons (list (car l) (cadr l))
(split (cddr l))))))
with double-cons being:
(define (double-cons l lol)
(list (cons (car l) (car lol))
(cons (cadr l) (cadr lol))))
double-cons:
(double-cons '(a 1) '((b c) (2 3)))
; => '((a b c) (1 2 3))
Other double-cons definitions
This takes more lines but makes it easier to read:
(define (double-cons l lol)
(let ((e1 (car l))
(e2 (cadr l))
(l1 (car lol))
(l2 (cadr lol)))
(list (cons e1 l1) (cons e2 l2))))
Or a double-cons which conses even more elements and lists in parallel:
(define (parallel-cons l lol)
(map cons l lol))
; it is `variadic` and conses as many elements with their lists
; as you want:
(parallel-cons '(1 a A '(a)) '((2 3) (b c d e) (B C) ((b) (c))))
; '((1 2 3) (a b c d e) (A B C) ('(a) (b) (c)))
; this combination of `map` and `cons` is used in the shortest solution above.

Sum of all numbers in a list at the top level

I'm new to Scheme and I've spent about a week on this.
Write a Lisp function sumlist which takes a list and returns the sum of all the numbers in the list, at the top level. Thus,
(sumlist '(1 2 (3) (4 a) nil b 5)) should return 1+2+5=8. The numbers 3 and 4 are not at the top level. Use number? to check if a thing is a number."
This is what I have so far. It can recognize whether something is a number or not, but I can't get it to only add up the numbers on the top level.
(define (sumlist lst)
(cond ((null? lst) 0)
((number? lst) lst)
((list? lst)
(+ (sumlist (car lst)) (sumlist (cdr lst))))
(#t 0)))
; no values returned
> (sumlist '(1 2 (3) (4 a) nil b 5))
15
Any help is appreciated.
EDIT: Both Jedi's and Daniel's answers work. Thank you both very much.
I think it can be a bit simpler:
(define (sumlist lst)
(cond
((null? lst) 0)
((number? (car lst)) (+ (car lst) (sumlist (cdr lst))))
(else (sumlist (cdr lst)))))
Since you only care if an element is a number or not, you only have 3 cases.
(define (sumlist lst)
(cond ((null? lst) 0) ;; list is empty, we're done ;;
((number? (car lst)) (+ (car lst) (sumlist (cdr lst)))) ;; the first item is a number, so we add it to the rest
(else (sumlist (cdr lst))) ;; the first item was not a number, we just check the rest of the list
))

List order after duplicate filtering

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.
(define (inlist L n)
(cond
((null? L) #f)
((= (car L) n) #t)
(else (inlist (cdr L) n))
))
(define (uniquelist L)
(cond
((null? L) '())
((= 1 (length L)) L)
((inlist (cdr L) (car L)) (uniquelist (cdr L)))
(else (cons (car L) (uniquelist (cdr L))))
))
So..
(uniquelist '(1 1 2 3)) => (1 2 3)
...but...
(uniquelist '(1 2 3 1)) => (2 3 1)
Is there a simple alternative that maintains the order of the first instance of each duplicate?
The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:
(define (uniquelist L)
(let loop ([lst (reverse L)] [acc empty])
(cond [(empty? lst)
acc]
[(member (first lst) (rest lst))
(loop (rest lst) acc)]
[else
(loop (rest lst) (cons (first lst) acc))])))
Or we can write the same procedure using standard Scheme, as shown in SICP:
(define (uniquelist L)
(let loop ((lst (reverse L)) (acc '()))
(cond ((null? lst)
acc)
((member (car lst) (cdr lst))
(loop (cdr lst) acc))
(else
(loop (cdr lst) (cons (car lst) acc))))))
The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:
(uniquelist '(1 1 2 3))
=> '(1 2 3)
(uniquelist '(1 2 3 1))
=> '(1 2 3)

Resources