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)))
))
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 :)
(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)))
I defined a function called zip which took two lists as parameters and returned a list of pairs.
(define (zip list1 list2)
(if (null? list1)
'()
(cons (list (cons (car list1) (car list2)))
(zip (cdr list1) (cdr list2)))))
(zip (list 1 3 5) (list 2 4 6))
> (((1 . 2)) ((3 . 4)) ((5 . 6)))
Now I'm basically having trouble writing the inverse function of this. This is what I have so far. This function needs to output a list of two lists. I only attempted at making the first of the two lists to make it easier for myself but the output is not what I want.
(define (unzip u-list)
(if (null? u-list)
'()
(list (car (car (car u-list))) (unzip(cdr u-list)))))
(unzip (zip (list 1 3 5) (list 2 4 6)))
> (1 (3 (5 ())))
Any help would be appreciated...
I believe there's a problem with your implementation of zip, did you notice that you're returning a list of single-element lists of pairs? returning a list of pairs makes more sense:
(define (zip lst1 lst2)
(if (null? lst1)
'()
(cons (cons (car lst1) (car lst2))
(zip (cdr lst1) (cdr lst2)))))
Or even better, let's use the map higher-order function for a shorter, more idiomatic solution:
(define (zip lst1 lst2)
(map cons lst1 lst2))
Regarding unzip: it's easier if we split the problem in parts - let's get the first element of each pair, then the second element of each pair, and finally build a list with the answer. Try this:
(define (unzip lst)
(define (firsts lst)
(if (null? lst)
'()
(cons (caar lst)
(firsts (cdr lst)))))
(define (seconds lst)
(if (null? lst)
'()
(cons (cdar lst)
(seconds (cdr lst)))))
(list (firsts lst) (seconds lst)))
But once again, we're reinventing the wheel. Let's just use built-in functions to write a simpler answer:
(define (unzip lst)
(list (map car lst) (map cdr lst)))
Anyway, now unzip is the inverse of zip:
(zip '(1 3 5) '(2 4 6))
=> '((1 . 2) (3 . 4) (5 . 6))
(unzip '((1 . 2) (3 . 4) (5 . 6)))
=> '((1 3 5) (2 4 6))
As you make it with pairs it's somewhat more difficult but not much:
(define (zip-pair a b)
(map cons a b))
(define (unzip-pair zipped-pair)
(list (map car zipped-pair)
(map cdr zipped-pair)))
zip is usually implemented with apply and map and takes list and produce list of lists, like this:
(define (zip . lists)
(apply map list lists))
(zip '(1 2 3) '(a b c)) ; ==> ((1 a) (2 b) (3 c))
Though this will make lists and not pairs. However a unzip is almost the same except that you will take a list of lists instead of variable number of arguments:
(define (unzip1 zipped-list)
(apply map list zipped-list))
; or reuse zip
(define (unzip1 zipped-list)
(apply zip zipped-list))
(unzip1 '((1 a) (2 b) (3 c))) ; ==> ((1 2 3) (a b c))
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 am trying to write a scheme function that takes a list of the form:
((#f ((1 1) (2 1)))
(#f ((1 3) (5 1)))
(#f ((1 4) (7 1)))
)
and removes all the #f to give a list like:
( ((1 1) (2 1))
((1 3) (5 1))
((1 4) (7 1))
)
I have tried the following code but cannot get it to work:
(define meth
(lambda lst
(if (equal? (cdr lst) '())
(cdr (car lst))
(cons (list-ref (car lst) 1) (meth (cdr lst))))))
Does anyone know how to do this? Thanks.
You can just use map to apply the cdr function to each sublist in the list, like this: (map cdr lst). However this will give you
( (((1 1) (2 1)))
(((1 3) (5 1)))
(((1 4) (7 1)))
)
for your sample input, which is one level of nesting more than your sample output. So to get your sample output, use list-ref to get the second element of each sublist:
(define (meth lst) (map (lambda (x) (list-ref x 1)) lst))
Edit: As Eli Barzilay helpfully pointed out, there is the cadr function to get the second element of a list, so this can be shortened to:
(define (meth lst) (map cadr lst))
Here is a way to do it more closely to what you had:
(define meth
(lambda (lst)
(cond
((null? lst) '())
((cons (cadr (car lst)) (meth (cdr lst))))
)
)
)
(define a '(
(#f ((1 1) (2 1)))
(#f ((1 3) (5 1)))
(#f ((1 4) (7 1)))
))