Change an element in a list using scheme [duplicate] - list

This question already has answers here:
Searching and replacing n element on list - scheme
(2 answers)
Closed 8 years ago.
I want to change element in a list, >(change '(1 2 2 4) 2 5) so that the remaining elements in
the list will be (1 5 4).
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
(((equal? (car mylist) num) (cons val))
(change (cdr mylist) num val))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))

So I changed the excessive and missing parens like I hinted in the comments and pressed CTRL+i and this is the result:
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
((equal? (car mylist) num) (cons val
(change (cdr mylist) num val)))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))
Notice how (change ...) is the second argument to cons and it is placed right under on the same margin as val? Identation is very important for spotting errors so do press CTRL+i a lot! I would have moved the whole thing a little like this though:
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
((equal? (car mylist) num)
(cons val
(change (cdr mylist) num val)))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))
Still. Se how (cons is rigth under (equal.. and not under the first paren while (else is? The identation tells you where cond clauses start and the structure of the code.
Looking at the code presented in your question the identation doesn't match the actual code since then (else..) would be in the (change.. list. It was actually impossible for me to see what was wrong before I reidented it.

Related

Recursive processing of list elements in LISP

Here is a task: a list is given, some of the elements are also lists. It's nescessary to replace the nested lists with the sum of the numbers in them, if all of them are even, using recursion. For example:
(1 2 NIL (2 4 6) 5 7) -> (1 2 NIL 12 5 7)
if the parent list matches the condition after the transformation:
(2 2 (4 4) (2 2)) -> (2 2 8 4) -> 16
Now i have the following code:
;; check for all list elements are even
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst)) (evenp (car lst))) (is-even-list (cdr lst)))
(t nil)
)
)
;; list summing
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst) (sum-list (cdr lst))))
)
)
;; main func
(defun task (lst)
(cond ((null lst) nil)
((atom (car lst)) (cons (car lst) (task (cdr lst))))
((is-even-list (car lst)) (cons (list (sum-list (car lst))) (task (cdr lst))))
(t (cons (task (car lst)) (task (cdr lst))))
)
)
But now it processes only the “lowest” level of the list if it exists:
(2 4) -> (2 4)
(2 (2 4 6) 6) -> (2 12 6)
(2 (4 (6 8) 10) 12) -> (2 (4 14 10) 12)
(2 (4 6) (8 10) 12) -> (2 10 18 12)
How can i change this code to get "full" processing?
It's definitely not the best solution but it works:
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst)) (evenp (car lst))) (is-even-list (cdr lst)))
(t nil)
)
)
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst) (sum-list (cdr lst))))
)
)
(defun test (lst)
(dotimes (i (list-length lst))
(cond
((not (atom (nth i lst))) (setf (nth i lst) (test (nth i lst))))
)
)
(cond
((is-even-list lst) (setf lst (sum-list lst)))
((not (is-even-list lst)) (setf lst lst))
)
)
Here's a solution which I think meets the requirements of the question: recursively sum a list each element of which is either an even number or a list meeting the same requirement. It also does this making only a single pass over the structure it is trying to sum. For large lists, it relies on tail-call elimination in the implementation which probably is always true now but is not required to be. sum-list-loop could be turned into something explicitly iterative if not.
(defun sum-list-if-even (l)
;; Sum a list if all its elements are either even numbers or lists
;; for which this function returns an even number. If that's not
;; true return the list. This assumes that the list is proper and
;; elements are numbers or lists which meet the same requirement but
;; it does not check this in cases where it gives up for other
;; reasons first: (sum-list-if-even '(2 "")) signals a type error
;; (but (sum-list-if-even '(1 "")) fails to do so)
(labels ((sum-list-loop (tail sum)
(etypecase tail
(null sum) ;all the elements of '() are even numbers
(cons
(let ((first (first tail)))
(etypecase first
(integer
;; Easy case: an integer is either an even number
;; or we give up immediately
(if (evenp first)
(sum-list-loop (rest tail) (+ sum first))
;; give up immediately
l))
(list
;; rerurse on the car ...
(let ((try (sum-list-if-even first)))
;; ... and check to see what we got to know if
;; we should recurse on the cdr
(if (not (eq try first))
(sum-list-loop (rest tail) (+ sum try))
l)))))))))
(sum-list-loop l 0)))
Allow me to show some improvements on your own answer.
First, use conventional formatting: no dangling parentheses, bodies indented two spaces, other argument forms aligned. Use appropriate line breaks.
(defun is-even-list (lst)
(cond ((null lst) t)
((and (numberp (car lst))
(evenp (car lst)))
(is-even-list (cdr lst)))
(t nil)))
(defun sum-list (lst)
(cond ((null lst) 0)
(t (+ (car lst)
(sum-list (cdr lst))))))
(defun test (lst)
(dotimes (i (list-length lst))
(cond ((not (atom (nth i lst)))
(setf (nth i lst) (test (nth i lst))))))
(cond ((is-even-list lst) (setf lst (sum-list lst)))
((not (is-even-list lst)) (setf lst lst))))
The first function checks two things: that every element is a number, and that every element is even. In this context, the first condition mainly means: no sublists.
(defun flat-all-even-p (list)
(and (every #'numberp list)
(every #'even list)))
The second function sums a list and assumes that all elements are numbers (sublists would signal an error here).
(defun sum (list)
(reduce #'+ list))
The third function does not test, it sums. Note that it only accidentally returns the answer, since setf returns the value it sets. Another problem is that you do index lookup on lists in a loop, which is very inefficient. Finally, you modify the list you were given, which will surprise your caller.
(defun sum-if-all-even (tree)
(if (listp tree)
(let ((recursed-tree (mapcar #'sum-if-all-even tree)))
(if (flat-all-even-p recursed-tree)
(sum recursed-tree)
recursed-tree))
tree)

Permutations of a list in scheme, works for numbers but not character as elements in list

I'm trying to do a program in scheme for a school assignment. Given a list, it's supposed to return all given permutations of that list. My issue is that I don't know why it would work for numbers but not characters. Doesn't seem like it would change any of the logic!
Here is my code:
(define (remove1 x lst)
(cond
((null? lst) '())
((= x (car lst)) (remove1 x (cdr lst)))
(else (cons (car lst)
(remove1 x (cdr lst))))))
(define (permute lst)
(cond
((= (length lst) 1) (list lst))
(else (apply append (map (lambda (i)
(map (lambda (j) (cons i j))
(permute (remove1 i lst))))
lst)))))
(permute '(1 2 3))
= is used for comparing numbers; for more general comparisons, use eq?, equal? or (as has been suggested) eqv?.

Take out all occurences of element in list

I have this code:
(define remove
(λ (x y)
(cond
((null? y) '())
((eq? x (car y)) (delete x (cdr y)))
(else (cons (car y) (delete x (cdr y))))
)))
Input: (remove 'c '(w((x)(c q)(((o))))w))
This will not go inside the inner parenthesis. If I try to remove 'w', it will remove all occurrences of it because they are outside of the parenthesis. So, I can't take out anything from the inside.
The solution is a bit more elaborate, you'll have to use the template for traversing a list of lists. Also, is better to use equal? instead of eq?, consult the documentation to understand the differences. A possible implementation follows, I took the liberty of renaming the parameters to something more meaningful:
(define remove
(λ (ele lst)
(cond
((null? lst) '()) ; if the list is empty then we're done
((not (pair? (car lst))) ; if the first element is an atom
(if (equal? (car lst) ele) ; check if it's the one we're looking for
(remove ele (cdr lst)) ; if so we skip over it, eliminating it
(cons (car lst) (remove ele (cdr lst))))) ; otherwise we add it
(else (cons (remove ele (car lst)) ; else advance recursion
(remove ele (cdr lst))))))) ; over both `car` and `cdr`
Now it works as expected:
(remove 'c '(w ((x) (c q) (((o)))) w))
=> '(w ((x) (q) (((o)))) w)

Return the second element for every element in a list

Let's say we have this list '( (4 (1 2)) (5 (5 5)) (7 (3 1)) (1 (2 3)))
I am trying to write smth in Scheme in order to get the second element for every element in the list.. So the result will look like '( (1 2) (5 5) (3 1) (2 3))
I have this code so far..
(define (second list1)
(if (null? (cdr list1))
(cdr (car list1))
((cdr (car list1))(second (cdr list1)))))
Here's a straightforward solution:
(define (seconds lst)
(map cadr lst))
In general, when you want to transform every element of a list, map is the way to go.
All you need to do is map the built-in function second onto the list lst:
(map second lst)
Your error is that you lack an operator, perhaps cons. If you look at the consequent:
((cdr (car list1))(second (cdr list1)))
So Scheme expects (cdr (car list)) to be a procedure since it's in operator position in the form, but since it isn't you get an error. In addition (cdr (car x)) == cdar wont take the second element in every element but the tail of each element. cadar is what you're lookig for.
(define (second list1)00+
(if (null? (cdr list1))
(cons (cadar list1) '())
(cons (cadar list1) (second (cdr list1)))))
It will fail for the empty list. To fix this you let the consequemt take care of every element and the base case only to stop:
(define (second list1)
(if (null? list1)
'()
(cons (cadar list1) (second (cdr list1)))))
The result for a list will be the same. There is a procedure called map. It supports several list arguments, but the implementation for one is:
(define (map fun lst)
(if (null? lst)
'()
(cons (fun (car lst)) (map fun (cdr lst)))))
Looks familiar? Both make a list based on each element, but map is generic. Thus we should try to make (fun (car lst)) do the same as (cadar lst).
(define (second lst)
(map cadr lst)) ; (cadr (car x)) == (cadar x)
There you have it. Chris beat me to it, but I'd like to comment one of the other answers that uses the abbreviation second. It's defined in racket/base and the library SRFI-1, but it's not mentioned in the last Scheme reports. I.e. some implementations might require an extra library to be imported for it to work.

How to break (11 (12 13)) using Car and Cdr in Scheme

I need to return from a list only those values which are odd so I am trying to break my list using car and cdr functions. I have a recursive funciton call that checks if the Car returns a list then further break it using car and cdr , otherwise just pass the first element to a function call check if Odd.
The problem with the special case (10 11 (12 13)) is that
car returns 10
cdr returns (11 (12 13))
then in second iteration
car returns (11 (12 13))
cdr returns (11 (12 13))
so How can i further break my list using car and cdr. I need to preserve the brackets in my final answer as well as only return the list having odd values of integers.
for a function that needs to work on an arbitrary nested list I find it easy to first write the flat list version (filter-odd in our case) and then edit it to produce the nested version (I will call it filter-odd*)
First for normal filter-odd
(define filter-odd
(lambda (ls)
(cond
[(null? ls) '()]
[(odd? (car ls)) (cons (car ls) (filter-odd (cdr ls)))]
[else (filter-odd (cdr ls))])))
Now for filter-odd* (one right-hand side will be left as an exercise (though it seems like you know the answer from your question))
(define filter-odd*
(lambda (ls)
(cond
[(null? ls) '()]
[(list? (car ls)) #| Do something with both car and cdr of ls |# ]
[(odd? (car ls)) (cons (car ls) (filter-odd* (cdr ls)))]
[else (filter-odd* (cdr ls))])))
As a note, this design pattern can be used to help write any recursive program and convert it from only working on flat lists to working on arbitrarily deep lists.
Here's a general solution, for lists with an arbitrary level of nesting:
(define (odds-list lst)
(cond ((null? lst) '()) ; the list is empty
((not (list? (car lst))) ; first element is not a list
(if (odd? (car lst)) ; element is odd
(cons (car lst) (odds-list (cdr lst))) ; build the returned list
(odds-list (cdr lst)))) ; element is even
(else (cons (odds-list (car lst)) ; first element is a list
(odds-list (cdr lst))))))
Notice that three cases need to be considered:
If the list is empty
If the first element of the list is not a list
If the first element of the list is a list
For the second case, two further cases need to be considered:
If the element is odd, then we add it to the list returned
If the element is even, we skip it and continue with the next element
Here's my take:
(define filter*
(lambda (e f)
(cond ((pair? e)
(append (filter* (car e) f)
(filter* (cdr e) f)))
((null? e) '())
((f e) (list e))
(else '()))))
and then you can do:
> (filter* '(1 (2 . 3) ((4 . 5))) even?)
(2 4)
> (filter* '(1 (2 . 3) ((4 . 5))) odd?)
(1 3 5)