(define ls2 '((james (1 2 3) (4 5 6) (8 5 6))
(daren (7 8 9) (2 6 4))
))
(define (delete name lst clear)
(if (equal? (caar ls2) name) (clear (cdar lst))
(delete name (cdr lst) clear)))
(define (clear lst)
(if (null? lst) #t (remove (car lst) lst)))
(delete 'james ls2 clear)
If james is matched with an element of list then (1 2 3) (4 5 6) (8 5
6) must be clear. I can just clear the (1 2 3) and i want to clear (4
5 6) (8 5 6) each by each recursively. However i can't succesive that.
I need an emergency help, please.
The clear procedure you wrote won't work, remove creates a new list where the removed element isn't present, but the original remains intact. Try this instead:
(define (delete name lst)
(cond ((null? lst) '())
((equal? (caar lst) name) ; if there's a match
(cons (list (caar lst)) ; clear all elements at once
(delete name (cdr lst)))) ; and advance recursion
(else (cons (car lst)
(delete name (cdr lst))))))
This is how it works: it creates a new list where the elements are removed, leaving the original list unmodified - that's how we write programs in Scheme:
(define lst '((james (1 2 3) (4 5 6) (8 5 6))
(daren (7 8 9) (2 6 4))))
(delete 'james lst)
=> '((james) (daren (7 8 9) (2 6 4)))
Related
I am working my first project in scheme and have come across an issue. In part of my requirements, I am required to append all top-level sublists
(e.g. '((1 2)(3 4 (5 6))) -> (1 2 3 4 (5 6)) and '((1 2 3)(4 5)) -> (1 2 3 4 5)
I've managed to get it working down to a single list, but this flattens all levels:
(cond
((null? lst)
lst)
((list? lst)
(append2(append-subs(car lst))(append-subs(cdr lst))))
(else
(cons lst '())))
Variations of this (eg. (else lst) run the error "object 6, passed as first arg to cdr, is not correct type". Another method I attempted is as follows:
(cond
((null? lst)
lst)
((>= (len (cdr lst)) 0)
(append2(append-subs(car (list lst)))(append-subs(cdr (list lst)))))
(else
lst)
Which infinitely loops. I'm at a bit of a stand still, so any help would be greatly appreciated. (Note: Use of functions other than those used here is forbidden. Limited to list, list?, if, cond, null? ...)
Your list '(e1 e2 e3) would be like this:
(cons e1 (cons e2 (cons e3 '())))
or if you like dotted notation:
'(e1 . (e2 . (e3 . ())))
Where en is eiter #f or #t for (list? en) Your assignment is to cons en onto the recursion with the same level while with a list you need to append the two.
Here is a general idea how to implement it with level as an input parameter:
;;; flatten a list a certain levels
;;; level of zero is identity
(define (flatten-level level lst)
(cond ((or (zero? level)
(null? lst))
lst)
;; pair? is faster but will fall through for dotted
((list? (car lst))
(append (flatten-level <??> <??>)
(flatten-level <??> <??>)))
(else
(cons <??>
(flatten-level <??> <??>)))))
(flatten-level 0 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> ((1 2) (3 (((4 . 3))) (5 (6))) . 7) (aka identity)
(flatten-level 1 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (((4 . 3))) (5 (6)) . 7)
(flatten-level 99 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (4 . 3) 5 6 . 7)
How about appending all elements of the top list:
(define (flatten-top-level lst)
(apply append lst))
Which is practically the definition of append*
If '(a (b) (c f)) is a valid input, (first element not a list) then you can try:
(define (flatten-top-level lst)
(apply append
(map (lambda (e) (if (list? e)
e
(list e))) ;make a list from the non-list element
lst)))
2nd option: Fold it!
(define (flatten-top-level lst)
(foldr append '() lst))
For a list (a b c d) where a, b, c, d are sub-lists; it is equal to:
(append a (append b (append c (append d '()))))
Extra: this is tail recurssive and therefore runs in linear time :)
I am trying to implement two functions : subterm and replace.
subterm takes two lists as arguments and prints the element in the first list that is reached after exhausting the second list.
For example, calling
(subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))
should return
8
I have come up with the following function which prints the nth element in the list :
(define (subterm list n)
(cond
((null? list) '())
((= n 1) (car list))
(else (subterm (cdr list) (- n 1)))))
replace takes 3 lists and returns the result of replacing the reached value with the rest of the list unchanged.
for example calling :
(replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))
should return :
'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))
Again, I came up with this code which replaces the nth element in the first list with the second list, leaving the rest of the first list unchanged :
#lang racket
(define (replace list elem n)
(cond
((empty? list) empty)
((eq? n 1) (cons elem (cdr list)))
(#t (cons (car list) (replace (cdr list) elem (- n 1))))))
How do I modify these functions to take in two lists?
Edit 1:
Some examples:
> (subterm '(1 2 3 4 5) '(3))
3
> (subterm '(1 2 3 4 5) '(2))
2
> (subterm '(1 2 (3 4 5) 6 7) '(3 2))
4
Consider this example:
> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))
8
In the above example, subterm takes 2 lists. Then it reads the second list. The second list basically tells subterm to return the 1st element (8) of the 2nd element ((8)) of the 2nd element (7 (8) 9 10) of the 4th element (6 (7 (8) 9 10) of the first list (1 2 (3 4 5) (6 (7 (8) 9 10))).
> (subterm '1 '())
1
> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '())
'(1 2 (3 4 5) (6 (7 (8) 9 10)))
> (replace '(1 2 3 4 5) '(6 7 8) '(3))
'(1 2 (6 7 8) 4 5)
> (replace '(1 2 3 4 5) '(6 7 8) '(2))
'(1 (6 7 8) 3 4 5)
Consider this example:
> (replace '(1 2 (3 4 5) 6 7) '(8 9) '(3 2))
'(1 2 (3 (8 9) 5) 6 7)
replace takes in three lists: first list is the list in which elements have to be replaced. The second list contains the new elements which have to be put into the first list. The third list contains the positions where the elements have to be replaced.
So, it basically replaced the 2nd element (4) of the 3rd element (3 4 5) of the first list (1 2 (3 4 5) 6 7).
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 1000 '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 (1000) 9 10)))
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 'x '())
'x
> (replace '1 '(2 3 4) '())
'(2 3 4)
First of all, you're using the name subterm for two different functions. Let's call the version you provided a code example for list-ref, and make the (car list) case happen when n = 0 instead of 1:
(define (list-ref list n)
(cond
((null? list) '())
((= n 0) (car list))
(else (list-ref (cdr list) (- n 1)))))
As it turns out, list-ref is already in the racket library, so you shouldn't really have to implement it in the first place. So using that, your subterm is trivial:
(define (subterm main-list path)
(match path
('() #f)
((list n) (list-ref main-list (sub1 n)))
((cons n rest) (subterm (list-ref main-list (sub1 n)) rest))))
I tried to code the replace procedure. With my knowledge I can say this is a hard one. However I managed to make it work at least with the example you gave. You could read it, try to understand it and then try to modify it to work with any other list. I believe you'll need an extra function to make it work properly.
#lang racket
(require racket/trace)
(define (replace list elem n)
(cond
((empty? list) empty)
((eq? n 1) (cons elem (cdr list)))
(#t (cons (car list) (replace (cdr list) elem (- n 1))))))
(define replace-with-lists
(λ (items replacement path res aux)
(letrec ([splits (list-split-at items (car path) '())])
(cond
((empty? (cdr path))
; (append
; (car (list-ref res 0))
; (list (append
; (car (list-ref res 1))
; (list (append (car aux)
; (replace (list-ref aux 1) replacement (car path))
; (list-ref aux 2)))))))
(let ([result (replace splits replacement 2)])
(replace aux
(append (car result)
(list (cadr result))
(caddr result)
)
2)))
(else
(replace-with-lists
(list-ref splits 1)
replacement
(cdr path)
(foldr cons (list (list
(list-ref splits 0)
(list-ref splits 2)))
res)
splits
)))
))
)
(define list-split-at
(λ (lst place res)
(cond
((empty? lst) res)
((= 1 place) (foldl cons
(list (cdr lst))
(foldr cons (list res) (list (car lst)))
))
(else
(list-split-at (cdr lst) (- place 1) (foldr cons (list (car lst)) res))
)
)))
(trace replace-with-lists)
Ok, I am in your programming languages class, and I am aware that this assignment is due tomorrow, so I don't want to help too much, or give you the answer. I will do my best to give you some hints in case you are still struggling. The following hints are for the replace function.
First, you need a base case. We are given this with the following
(replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 'x '())
'x
(replace '1 '(2 3 4) '())
'(2 3 4)
To do this, we just need a conditional statement that checks for an empty list. It is clear that if the last argument is an empty list, we need to "return" the second to last argument. (in your code this would be "elem" and "n")
Now comes the difficult part. It is really quite simply once you realize how many built in functions scheme/racket has. Here are the only ones I used, but they made solving the problem much much easier.
(append)
(list)
(take)
(drop)
(list-ref) //this one is more of a convenience than anything.
After the turn in date has passed, I will post my solution. Hope this helped.
EDIT: As this assignment was due a few minutes, I will post my solution as I don't think that would be considered cheating.
lang racket
(define (subterm term1 lat)
(cond
[(eqv? lat '()) term1]
[(eqv? (car lat)1) (subterm (car term1) (cdr lat))]
[else (subterm (cdr term1) (cons(-(car lat)1)(cdr lat)))])
)
(define (replace term1 term2 lat)
(cond
[(eqv? lat '()) term2]
[else (append(take term1 (-(car lat)1)) (list(replace (list-ref term1 (-(car lat)1)) term2 (cdr lat))) (drop term1 (car lat)))]))
Those are both functions.
First off, if anyone can find a question where this has already been answered, let me know. All I can find are functions that remove duplicates.
Anyhow, I am trying to write a scheme function (delete V L) that takes a value and a list as arguments, and removes that value from the list and all its sublists. For example, given the following input:
> (deep-delete 3 '(1 2 3 (4 3) 5 (6 (3 7)) 8))
It would yield:
(1 2 (4) 5 (6 (7)) 8)
So far, this is what I have written, but I know that the if statement (which is to check to see if the element is a sub-list, which implies it too must be operated on) must be placed incorrectly. Also, I cannot wrap my brain around where I should be using cons and where I shouldn't, because I'm still confused about tracking the return values of the recursion. Can someone please take a look and explain what I'm doing wrong?
(define (delete V L)
(if (list? (car L)) (cons (delete V (car L) (cdr L)))
(cond
((null? L) L)
((equal? V (car L)) (delete V (cdr L)))
(else (cons (car L) (delete V (cdr L))))))))
I have a few comments on your code:
First, in your if statement you use (car L) without checking if L is empty.
Also, in line 2 of your code, you do: (delete V (car L) (cdr L)),
but cons takes two arguments, not three. And you forgot to recursively call delete on the cdr.
You wanted:
(cons (delete V (car L)) (delete V (cdr L)))
Why not use a single cond? Since there are several cases, using cond will make the recursive structure of your algorithm more apparent, and errors easier to catch.
See below.
(define (del V L)
(cond ((null? L) L)
((list? (car L))
(cons (del V (car L)) (del V (cdr L))))
((equal? V (car L)) (del V (cdr L)))
(else (cons (car L) (del V (cdr L))))))
This will recursively delete V from L.
(del 3 '(1 2 3 (4 3) 5 (6 (3 7)) 8))
==> (1 2 (4) 5 (6 (7)) 8)
This is quite easy to achieve with folding; here's an example in Racket using foldr:
(define (deep-delete elt lst (test equal?))
(foldr (lambda (e r)
(if (list? e)
(cons (deep-delete elt e test) r)
(if (test elt e) r (cons e r))))
null
lst))
testing
> (deep-delete 3 '(1 2 3 (4 3) 5 (6 (3 7)) 8))
'(1 2 (4) 5 (6 (7)) 8)
This removes subtrees from a tree (including atomic ones):
(define (remove-element needle haystack)
(let rec ((haystack haystack))
(cond
((equal? needle haystack) '())
((not (pair? haystack)) haystack)
((equal? needle (car haystack)) (rec (cdr haystack)))
((equal? needle (cdr haystack)) (cons (rec (car haystack)) '()))
(else (cons (rec (car haystack))
(rec (cdr haystack)))))))
(remove-element 'atom 'atom) ; => ()
(remove-element '(1 2 3) '((1 2 3) 1 2 3)) ; => ()
(remove-element '(1 2 3) '((1 2 3) 4 5 6)) ; => (4 5 6)
(remove-element '(1 2 3) '(3 2 1 2 3)) ; ==> (3 2)
(remove-element '3 '((1 2 3) 1 2 3)) ; ==> ((1 2) 1 2)
(remove-element '(1 2 3) '(1 2 3 4)) ; ==> (1 2 3 4)
I have list in this form
( (1 3) (2 2) (3 1) (4 5) (5 1)))
and I want to delete an item let's say (3 1)
So the result will be
( (1 3) (2 2) (4 5) (5 1)))
I have written something like this and I do not know why it is not running correctly.
(define (deleteItem list item)
(cond
((equal? item (car list)) (cdr list))
(cons (car list)(deleteItem(cdr list) item))))
There's a built-in function for this, it's called remove:
(define lst
'((1 3) (2 2) (3 1) (4 5) (5 1)))
(remove '(3 1) lst)
=> '((1 3) (2 2) (4 5) (5 1))
… But I guess you need to implement it from scratch. Some suggestions for your code:
You should not use list as a parameter name, that'll clash with a built-in function. Let's call it lst instead
You're missing the base case necessary form most list procedures: what happens if the list is empty?
You're also missing the else part in the last condition
With all the above fixes in place, the procedure will work:
(define (deleteItem lst item)
(cond ((null? lst)
'())
((equal? item (car lst))
(cdr lst))
(else
(cons (car lst)
(deleteItem (cdr lst) item)))))
(deleteItem lst '(3 1))
=> '((1 3) (2 2) (4 5) (5 1))
The procedure already exists:
(remove '(3 1) '((1 3) (2 2) (3 1) (4 5) (5 1))))
Otherwise your procedure should look like this:
(define (deleteItem item list)
(cond
((empty? list) '())
((equal? item (car list)) (cdr list))
(else (cons (car list) (deleteItem item (cdr list))))))
You missed:
the base case, (empty? list)
the "else" in the final clause
and you shouldn't use list as a variable name because it shadows the build-in procedure list (but it will work).
1) if consider the input list may be a simple list, or you just want to delete the item in the top-level of a nested list
for example:
delete 2 from (1 2 3 4) will return (1 2 3)
delete 2 from (1 2 3 (2 3) 3 2 4) will return (1 3 (2 3) 3 4)
as we can see the 2nd example above, it just delete the item in the top-level of the nested list, within the inner list, we doesn't change it.
this code should be:
(define (deleteitem list1 item)
( cond
((null? list1) ’())
((equal? (car list1) item) (deleteItem (cdr list1) item))
(else (cons (car list1) (deleteitem (cdr list1) item)))
))
2) if consider the input list may be a nested list
for example:
input list: (1 2 3 (3 2 (2 4 (2 5 6) 2 5 6) 2 4) 2 3 (2 3 4))
and delete the element 2 in the input list
the output list should be: (1 3 (3 (3 (5 6) 5 6) 4) 3 (3 4))
and the code should be:
(define (delete2 list1 item)
( cond
((null? list1) '())
((pair? (car list1)) (con (delete2 (car list1) item) (delete2 (cdr list1) item)))
((equal? (car list1) item) (delete2 (cdr list1) item))
(else (cons (car list1) (delete2 (cdr list1) item)))
))
I need to replace an element from a list with another element in Scheme, but the problem is that the list where I need to replace can be nested.
For example, if I have the list '(1 (2 3 4 5) (6 7)) and I need to replace 5 with 9, my output should be '(1 (2 3 4 9) (6 7)).
Can you please help me with this problem?
There is a basic strategy for solving this kind of problem:
First, solve it for a flat list. i.e., write the function so that it works if the input list has no sublists.
Then, add a condition so that if the element you're inspecting is a list, then recurse into your function with that list.
Here's some skeletal code:
(define (replace lst from to)
(cond ((null? lst) '()) ;; end of input
((list? (car lst)) <???>) ;; encountered a sublist
((equal? (car lst) from) <???>) ;; found the element we're replacing
(else <???>))) ;; everything else
Notice that the second cond clause, (list? (car lst)), is the only thing that's new in your sublist-capable version.
here is a function:
(define (replace L new old)
(cond ;;((null? L) L)
((list? L)
(map
(lambda (lst) (replace lst new old))
L))
(else
(if (equal? L old)
new
L))))
examples of use:
> (replace '(1 (1 2 3 4 (5 6 3) 3 4)) 7 3)
'(1 (1 2 7 4 (5 6 7) 7 4))
> (replace '() 7 3)
'()
> (replace '(1 (1 2 3 4) 3 4) 7 3)
'(1 (1 2 7 4) 7 4)
or:
(define (replace L new old)
(if (list? L)
(map
(lambda (lst) (replace lst new old))
L)
(if (equal? L old)
new
L)))
example:
(replace '(1 (1 2 3 4 (5 6 3) 3 4)) 7 3) -> '(1 (1 2 7 4 (5 6 7) 7 4))