how to delete an element from a list
ex:- list=[1 2 3 4]
I have come up with some code.I think I got wrong somewhere.
(define delete item
(lambda (list)
(cond
((equal?item (car list)) cdr list)
(cons(car list)(delete item (cdr list))))))
Your code is almost correct.
The item also should be a parameter, so the function may begin with like this:
(define delete
(lambda (item list)
...
Also, your code needs paren around the cdr list and else in the last clause.
Then, the code may be like this:
(define delete
(lambda (item list)
(cond
((equal? item (car list)) (cdr list))
(else (cons (car list) (delete item (cdr list)))))))
Shido Takafumi wrote a tutorial about Scheme, Yet Another Scheme Tutorial.
In chapter 7, exercise 1, the 3rd problem.
A function that takes a list (ls) and an object (x) as arguments and returns
a list removing x from ls.
The author gave the solution code bottom of the page.
; 3
(define (remove x ls)
(if (null? ls)
'()
(let ((h (car ls)))
((if (eqv? x h)
(lambda (y) y)
(lambda (y) (cons h y)))
(remove x (cdr ls))))))
The code maybe difficult to comprehend for beginner.
It's same as the code below.
(define (rm x ls)
(if (null? ls)
'()
(if (eqv? x (car ls))
(rm x (cdr ls))
(cons (car ls)
(rm x (cdr ls))))))
This can delete the same elements in list. :D
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)))
))
This code seems to work just fine, but only deletes an element that should be in the list:
(define (delete element lst)
(let loop ([temp lst])
(if (= element (car temp)) (cdr temp)
(cons (car temp) (loop (cdr temp))))))
delete element from a list without nested lists
(define (remove item lst)
(define (filter-lst l)
(cond
((null? l) nil)
((= item (car l)) (filter-lst (cdr l)))
(else (cons (car l) (filter-lst (cdr l)))))
)
(if (null? lst) () (filter-lst lst))
)
;;; Tests
(remove 2 '(4 3 2))
; expect (4 3)
(remove 3 nil)
; expect ()
(remove 3 '(1 3 5))
; expect (1 5)
(remove 5 '(5 5 1 4 5 4))
; expect (1 4 4)
(define (deleteItem(list item))
(cond
((eq ? item (car(list)))cdr(list))
(cons(car(list)(deleteItem(cdr list)))
)
)
Related
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.
I'm trying to create a function that returns the adjacent duplicates of a list, for example (dups '(1 2 1 1 1 4 4) should return the list (1 4).
This is the code I came up with so far:
(define (dups lst)
(if (equal? (car lst)(car(cdr lst)))
(cons(cdr lst) '())
(dups(cdr lst))))
This function doesn't return all the adjacent duplicates, it only returns the first adjacent duplicates!
How can I fix it so that it returns all the adjacent duplicates of a list?
Thank you.
Once your code finds a duplicate, it stops processing the rest of the list: when the if test is true, it yields (cons (cdr lst) '()). Whether or not it finds a duplicate, it should still be calling dups to process the rest of the list.
Also: if your list has no duplicates, it it going to run into trouble.
Here's a simpler solution than the others posted:
(define (dups lst)
(if (< (length lst) 2)
; No room for duplicates
'()
; Check for duplicate at start
(if (equal? (car lst) (cadr lst))
; Starts w/ a duplicate
(if (or (null? (cddr lst)) ; end of list
(not (equal? (car lst) (caddr lst)))) ; non-matching symbol next
; End of run of duplicates; add to front of what we find next
(cons (car lst) (dups (cdr lst)))
; Othersise keep looking
(dups (cdr lst)))
; No duplicate at start; keep looking
(dups (cdr lst)))))
Basically this boils down to only keeping the elements which are the same as the previous one, but different from the next.
Here's an example implementation using a named let.
(define (adj-dups lst)
(let loop ((lst (reverse (cons (gensym) lst)))
(e-2 (gensym))
(e-1 (gensym))
(acc '()))
(if (null? lst)
acc
(let ((e-0 (car lst)))
(loop (cdr lst)
e-1
e-0
(if (and (eqv? e-2 e-1) (not (eqv? e-1 e-0)))
(cons e-1 acc)
acc))))))
(gensym) comes in handy here because it's a convenient way to initialise the working variables with something that's different from everything else, and filling up the initial list with a dummy element that needs to be added so that we don't miss the last element.
Testing:
> (adj-dups '())
'()
> (adj-dups '(1 1 4 4 1 1))
'(1 4 1)
> (adj-dups '(1 1 1 1 1))
'(1)
> (adj-dups '(1 2 1 1 1 4 4))
'(1 4)
> (adj-dups '(2 3 3 4 4 4 5))
'(3 4)
The most straightforward way I can think of to tackle this is with an internal procedure with an extra variable to keep track what the prior element was and a boolean to track if the element was repeated. You can then do a mutual recurstion between the helper and main function to build the answer one duplicate element at a time.
(define (dups lst)
(define (dups-helper x repeat? L)
(cond ((null? L)
(if repeat?
(list x)
'()))
((equal? x (car L))
(dups-helper x #t (cdr L)))
(else
(if repeat?
(cons x (dups L))
(dups L)))))
(if (null? lst)
'()
(dups-helper (car lst) #f (cdr lst))))
(dups (list 1 1 4 4 5 6 3 3 1))
;Value 43: (1 4 3)
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))
My problem is the butSecondLastAtom algorithm. It doesn't work because cdr doesn't comprehend an empty list. But I see no other way of writing the algorithm. It's at the end of the page. Everything works but when the last element of a list is a list.
http://lpaste.net/110959
The problem is in the recursive call of (cdr (cdr l)) but more in the 3rd condition. Idk what to do. I'm just going to stop tonight and start fresh in the morning.
((and (isAtom (second_last_element l)) (notAtom (last_element l)))
(cons
(car l)
(butSecondLastAtom (last_element l))))
I think the main problem in your code is the use of null? or cdr on the cdr of a list, both in flatten and in butLast. Don't do this; always use the procedures and predicates on the list itself.
I'd suggest the following:
Flattening the list
Most Schemes have a version of flatten build-in, which takes care of nested lists and improper lists. The version you implemented is not entirely correct (try (flatten '())), use this one:
(define (flatten lst)
(let loop ((lst lst) (res null))
(cond
((null? lst) res)
((pair? lst) (loop (car lst) (loop (cdr lst) res)))
(else (cons lst res)))))
> (flatten '(1 2 (3 (4 5 6))))
'(1 2 3 4 5 6)
> (flatten '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 5 6)
> (flatten '())
'()
Dropping the second last element
So this becomes much easier now, looping through a simple flat proper list while keeping track of the last (n-1) and second-last (n-2) element. An example implementation is:
(define (butSecondLastAtom lst)
(define flst (flatten lst))
(if (< (length flst) 2)
flst
(let loop ((flst (cddr flst)) (n-2 (car flst)) (n-1 (cadr flst)) (res null))
(if (null? flst)
(reverse (cons n-1 res)) ; here we drop the second-last element
(loop (cdr flst) n-1 (car flst) (cons n-2 res))))))
If you want to avoid going through the list twice (once for length, once for the loop), you can also keep track of the length yourself:
(define (butSecondLastAtom lst)
(define flst (flatten lst))
(let loop ((lst flst) (len 0) (n-2 #f) (n-1 #f) (res null))
(if (null? lst)
(if (< len 2)
flst
(reverse (cons n-1 res))) ; here we drop the second-last element
(loop (cdr lst) (add1 len) n-1 (car lst) (if (< len 2) null (cons n-2 res))))))
Testing
> (butSecondLastAtom '(1 2 (3 (4 5 6))))
'(1 2 3 4 6)
> (butSecondLastAtom '(1 2 (3 (4 5 (6)))))
'(1 2 3 4 6)
> (butSecondLastAtom '(((a))))
'(a)
> (butSecondLastAtom '())
'()
I'm trying to reverse a list, here's my code:
(define (reverse list)
(if (null? list)
list
(list (reverse (cdr list)) (car list))))
so if i enter (reverse '(1 2 3 4)), I want it to come out as (4 3 2 1), but right now it's not giving me that. What am I doing wrong and how can I fix it?
The natural way to recur over a list is not the best way to solve this problem. Using append, as suggested in the accepted answer pointed by #lancery, is not a good idea either - and anyway if you're learning your way in Scheme it's best if you try to implement the solution yourself, I'll show you what to do, but first a tip - don't use list as a parameter name, that's a built-in procedure and you'd be overwriting it. Use other name, say, lst.
It's simpler to reverse a list by means of a helper procedure that accumulates the result of consing each element at the head of the result, this will have the effect of reversing the list - incidentally, the helper procedure is tail-recursive. Here's the general idea, fill-in the blanks:
(define (reverse lst)
(<???> lst '())) ; call the helper procedure
(define (reverse-aux lst acc)
(if <???> ; if the list is empty
<???> ; return the accumulator
(reverse-aux <???> ; advance the recursion over the list
(cons <???> <???>)))) ; cons current element with accumulator
Of course, in real-life you wouldn't implement reverse from scratch, there's a built-in procedure for that.
Here is a recursive procedure that describes an iterative process (tail recursive) of reversing a list in Scheme
(define (reverse lst)
(define (go lst tail)
(if (null? lst) tail
(go (cdr lst) (cons (car lst) tail))))
(go lst ())))
Using substitution model for (reverse (list 1 2 3 4))
;; (reverse (list 1 2 3 4))
;; (go (list 1 2 3 4) ())
;; (go (list 2 3 4) (list 1))
;; (go (list 3 4) (list 2 1))
;; (go (list 4) (list 3 2 1))
;; (go () (list 4 3 2 1))
;; (list 4 3 2 1)
Here is a recursive procedure that describes a recursive process (not tail recursive) of reversing a list in Scheme
(define (reverse2 lst)
(if (null? lst) ()
(append (reverse2 (cdr lst)) (list (car lst)))))
(define (append l1 l2)
(if (null? l1) l2
(cons (car l1) (append (cdr l1) l2))))
Using substitution model for (reverse2 (list 1 2 3 4))
;; (reverse2 (list 1 2 3 4))
;; (append (reverse2 (list 2 3 4)) (list 1))
;; (append (append (reverse2 (list 3 4)) (list 2)) (list 1))
;; (append (append (append (reverse2 (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (append (reverse2 ()) (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (append () (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (list 4) (list 3)) (list 2)) (list 1))
;; (append (append (list 4 3) (list 2)) (list 1))
;; (append (list 4 3 2) (list 1))
;; (list 4 3 2 1)
Tail recursive approach using a named let:
(define (reverse lst)
(let loop ([lst lst] [lst-reversed '()])
(if (empty? lst)
lst-reversed
(loop (rest lst) (cons (first lst) lst-reversed)))))
This is basically the same approach as having a helper function with an accumulator argument as in Oscar's answer, where the loop binding after let makes the let into an inner function you can call.
Here's a solution using build-list procedure:
(define reverse
(lambda (l)
(let ((len (length l)))
(build-list len
(lambda (i)
(list-ref l (- len i 1)))))))
This one works but it is not a tail recursive procedure:
(define (rev lst)
(if (null? lst)
'()
(append (rev (cdr lst)) (car lst))))
Tail recursive solution:
(define (reverse oldlist)
(define (t-reverse oldlist newlist)
(if (null? oldlist)
newlist
(t-reverse (cdr oldlist) (cons (car oldlist) newest))))
(t-reverse oldlist '()))
Just left fold the list using cons:
(define (reverse list) (foldl cons null list))
This is also efficient because foldl is tail recursive and there is no need for append. This can also be done point-free (using curry from racket):
(define reverse (curry foldl cons null))
(define reverse?
(lambda (l)
(define reverse-aux?
(lambda (l col)
(cond
((null? l) (col ))
(else
(reverse-aux? (cdr l)
(lambda ()
(cons (car l) (col))))))))
(reverse-aux? l (lambda () (quote ())))))
(reverse? '(1 2 3 4) )
One more answer similar to Oscar's. I have just started learning scheme, so excuse me in case you find issues :).
There's actually no need for appending or filling the body with a bunch of lambdas.
(define (reverse items)
(if (null? items)
'()
(cons (reverse (cdr items)) (car items))))
I think it would be better to use append instead of cons
(define (myrev l)
(if (null? l)
'()
(append (myrev (cdr l)) (list (car l)))
)
)
this another version with tail recursion
(define (myrev2 l)
(define (loop l acc)
(if (null? l)
acc
(loop (cdr l) (append (list (car l)) acc ))
)
)
(loop l '())
)