I'm pretty new to lisp and I want to make function that every even-indexed element replace it with new one element list that holds this element. For example
(1 2 3 4 5) -> (1 (2) 3 (4) 5), (1 2 3 4 5 6) -> (1 (2) 3 (4) 5 (6))
Right now I came up with solution that each of the lements put in it's own list, but I cant get exactly how to select every even-indexed element:
(DEFUN ON3 (lst)
((ATOM (CDR lst)) (CONS (CONS (CAR lst) NIL) NIL))
(CONS (CONS (CAR lst) NIL) (ON3 (CDR lst))))
Your code doesn't work. You'll need to use if or cond such that the code follow one of the paths in it. Right now you have an error truing to call a function called (atom (cdr lst)). If it had been something that worked it would be dead code because the next line is always run regardless. It is infinite recursion.
So how to count. You can treat every step as a handle on 2 elements at a time. You need to take care of the following:
(enc-odds '()) ; ==> ()
(enc-odds '(1)) ; ==> (1)
(enc-odds '(1 2 3 ...) ; ==> (1 (2) (enc-odds (3 ...))
Another way is to make a helper with extra arguments:
(defun index-elements (lst)
(labels ((helper (lst n)
(if (null lst)
lst
(cons (list (car lst) n)
(helper (cdr lst) (1+ n))))))
(helper lst 0)))
(index-elements '(a b c d))
; ==> ((a 0) (b 1) (c 2) (d 3))
For a non-recursive solution, loop allows for constructing simultaneous iterators:
(defun every-second (list)
(loop
for a in list
for i upfrom 1
if (evenp i) collect (list a)
else collect a))
(every-second '(a b c d e))
; ==> (A (B) C (D) E)
See http://www.gigamonkeys.com/book/loop-for-black-belts.html for a nice explanation of loop
Related
I just started to learn Common Lisp and this is my first functional programming language.
I am trying to learn about iterating through lists. I wrote these two functions:
(defun reverseList (liste)
(defvar reversedList(list))
(loop for i downfrom (-(length liste)1) to 0 do
(setf reversedList (append reversedList (list(nth i liste)))))
reversedList ;return
)
(defun countAppearance(liste element)
(defvar count 0)
(loop for i from 0 to (-(length liste) 1)do
(if (= (nth i liste) element)
(setf count (+ count 1))))
count
)
Both work fine for a regular list(ex: (1 3 5 7 3 9) but I want them to work for nested lists too.
Examples:
countAppearance - Input: (1 (3 5) (3 7 8) 2) 3 -> Expected output:2
reverseList - Input: (1 (2 3)) -> Expected output: ((3 2) 1)
Before I will show you solutions for nested lists, some notes about your code:
There is already function reverse for non-nested lists, so you don't have to reinvent the wheel.
=> (reverse (list 1 2 3 4 5))
(5 4 3 2 1)
If you need some local variables, use let or let*.
Lisp uses kebab-case, not camelCase, so rename reverseList as reverse-list and so on.
For (setf ... (+ ... 1)), use incf.
For iterating over list, use dolist.
Function count-occurrences can be written using recursion:
(defun count-occurrences (lst elem)
(cond ((null lst) 0)
((= (car lst) elem) (+ 1 (count-occurrences (cdr lst) elem)))
(t (count-occurrences (cdr lst) elem))))
CL-USER 3 > (count-occurrences (list 1 2 3 1 2 3) 2)
2
Or it can be written with let, dolist and incf:
(defun count-occurrences2 (lst elem)
(let ((count 0))
(dolist (e lst)
(when (= e elem) (incf count)))
count))
CL-USER 4 > (count-occurrences2 (list 1 2 3 1 2 3) 2)
2
Solutions for nested lists use recursion:
(defun deep-reverse (o)
(if (listp o)
(reverse (mapcar #'deep-reverse o))
o))
CL-USER 11 > (deep-reverse '(1 (2 3)))
((3 2) 1)
(defun deep-count (lst elem)
(cond ((null lst) 0)
((listp (car lst)) (+ (deep-count (car lst) elem)
(deep-count (cdr lst) elem)))
((= (car lst) elem) (+ 1 (deep-count (cdr lst) elem)))
(t (deep-count (cdr lst) elem))))
CL-USER 12 > (deep-count '(1 (3 5) (3 7 8) 2) 3)
2
Welcome to functional programming.
Firstly, there are some problems with the code that you have provided for us. There are some spaces missing from the code. Spaces are important because they separate one thing from another. The code (xy) is not the same as (x y).
Secondly, there is an important difference between local and global variables. So, in both cases, you want a local variable for reversedList and count. This is the tricky point. Common Lisp doesn't have global or local variables, it has dynamic and lexical variables, which aren't quite the same. For these purposes, we can use lexical variables, introduced with let. The keyword let is used for local variables in many functional languages. Also, defvar may not do what you expect, since it is way of writing a value once, which cannot be overwritten - I suspect that defparameter is what you meant.
Thirdly, looking at the reverse function, loop has its own way of gathering results into a list called collect. This would be a cleaner solution.
(defun my-reverse (lst)
(loop for x from (1- (length lst)) downto 0 collect (nth x lst)))
It can also be done in a tail recursive way.
(defun my-reverse-tail (lst &optional (result '()))
(if lst
(my-reverse-tail (rest lst) (cons (first lst) result))
result))
To get it to work with nested lists, before you collect or cons each value, you need to check if it is a list, using listp. If it is not a list, just add it onto the result. If it is a list, add on instead a call to your reverse function on the item.
Loop also has functionality to count items.
I am attempting to write a function that calls a list recursively and reverses its order. However I need to make the function operate every other recursive level and I am attempting to pass boolean arguments to use as a flag. I am very new to Lisp and keep getting an Undefined function B error.
(defun revList (L b)
(cond ((null L) nil)
((b T)
(append (revList (cdr L nil))
(list (car L))))
((b nil)
(append (revList (cdr L T))
(list (car L))))))
(print (revlist '(1 (2 3) (4 (5 6)) (7 (8 (9 10)))) t))
The first problem, and the reason for the reported error message Undefined function B is that some test forms in the cond form are attempting to call a function b which has not been defined. In a cond form the test forms are evaluated, and the result is used to determine which branch should be used. When (b T) or (b nil) are evaluated, it is expected that b is a function or macro. Instead you should use an expression which evaluates to either a true value or nil here.
There is another problem of misplaced parentheses around a couple of calls to cdr: (cdr L nil) and (cdr L T).
Once these problems are fixed, the code looks like this:
(defun revList (L b)
(cond ((null L) nil)
(b
(append (revList (cdr L) nil)
(list (car L))))
(t
(append (revList (cdr L) t)
(list (car L))))))
I'm going to rewrite the above function using some better names to make things a bit more clear. Note that the idiomatic way to introduce an else clause into a cond form is to use t as the test form in the final clause:
(defun rev-helper-1 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-1 (cdr xs) nil)
(list (car xs))))
(t
(append (rev-helper-1 (cdr xs) t)
(list (car xs))))))
This code compiles and runs, but probably does not do what is expected. When reverse-p is true the code does exactly the same thing as when it is false, except that the sense of reverse-p is flipped. So the code always reverses its input:
CL-USER> (rev-helper-1 '(1 2 3 4) t)
(4 3 2 1)
CL-USER> (rev-helper-1 '(1 2 3 4) nil)
(4 3 2 1)
Further, this code does not descend into nested lists:
CL-USER> (rev-helper-1 '(1 2 3 4 (a b c d (5 6 7 8))) nil)
((A B C D (5 6 7 8)) 4 3 2 1)
It isn't entirely clear from the OP post whether the desired goal is to reverse list elements on alternate recursive calls, or to reverse list elements in alternate levels of nesting. I suspect that the second goal is the correct one.
Reversing on Alternate Recursive Calls
To reverse list elements on alternating recursive calls, the code needs to cons the first element of the list back onto the front of the "reversed" remainder of the list whenever it is in a non-reversing call. In this way, every other element will be moved to the back of the list, and those moved to the back will be in reverse order in the final list.
(defun rev-helper-2 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-2 (cdr xs) nil)
(list (car xs))))
(t
(cons (car xs)
(rev-helper-2 (cdr xs) t)))))
CL-USER> (rev-helper-2 '(1 2 3 4) t)
(2 4 3 1)
Reversing in Alternate Levels of Nesting
To reverse in alternate levels of nesting, the code needs distinguish between atoms and lists in the input.
If the first element of a list is an atom, and if the current level is a reversing level, then the first element is wrapped in a list and appended to the result of reversing the rest of the level. Otherwise, if the first element is an atom, and the current level is not a reversing level, then the first element is consed onto the front of "reversing" the rest of the level. In this second case "reversing" the rest of the level will not change the ordering of elements at this level, because reverse-p will be false for non-reversing levels; but the code still needs to walk over the list to see if any elements at this level are lists which require further processing.
Otherwise, the first element is a list. If the current level is a reversing level, then the first element must be "reversed", i.e., processed by the reversing function, then wrapped in a list and appended to the end of reversing the rest of the list. Otherwise the current level is not a reversing level, so the first element must be processed by the reversing function and consed onto the front of "reversing" the rest of the list.
(defun rev-helper-3 (xs reverse-p)
(cond ((null xs) nil)
((atom (car xs))
(if reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (car xs)))
(cons (car xs)
(rev-helper-3 (cdr xs) nil))))
(reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (rev-helper-3 (car xs) nil))))
(t
(cons (rev-helper-3 (car xs) t)
(rev-helper-3 (cdr xs) nil)))))
Using a let form to bind the results of (car xs) and (cdr xs) to a couple of descriptive identifiers reduces the number of calls to car and cdr and makes this a bit easier to read:
(defun rev-helper-4 (xs reverse-p)
(if (null xs) nil
(let ((first (car xs))
(rest (cdr xs)))
(cond ((atom first)
(if reverse-p
(append (rev-helper-4 rest t)
(list first))
(cons first
(rev-helper-4 rest nil))))
(reverse-p
(append (rev-helper-4 rest t)
(list (rev-helper-4 first nil))))
(t
(cons (rev-helper-4 first t)
(rev-helper-4 rest nil)))))))
Let's write a convenience function to make it nicer to call rev-helper-4:
(defun rev-alt (xss)
(rev-helper-4 xss t))
CL-USER> (rev-alt '(1 2 3 4))
(4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d)))
((A B C D) 4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d (5 6 7 8))))
((A B C D (8 7 6 5)) 4 3 2 1)
CL-USER> (rev-alt '(1 (2 3) (4 (5 6)) (7 (8 (9 10)))))
((7 ((9 10) 8)) (4 (6 5)) (2 3) 1)
I'm new to LISP and I'm trying to create a recursive function that pairs the elements within a list. I'm stuck on the last part of my function with adding in the recursion.
(defun pairup (L)
(cond((null L) nil))
(list (cons (car L) (cadr L)(pairup(cdr L)))))
I know that (pairup(cdr L)))))) will show an error because its a third argument going into cons. Not sure how to add in the function again =/
INPUT: (pairup'(1 2 3 4))
OUTPUT: ((1 2) (3 4))
Here is the function:
(defun pairup (l)
(cond ((null l) nil)
((null (cdr l)) (list l))
(t (cons (list (car l) (cadr l))
(pairup (cddr l))))))
(pairup '(1 2 3 4)) ; produces ((1 2) (3 4))
(pairup '(1 2 3)) ; produces ((1 2) (3))
Note that the second branch of the cond is to terminate the recursion when only one element is left, and this is necessary if the initial list has an odd number of elements. The syntax of the cond requires that the first form of a branch be always a condition, and in the last branch the condition is t to catch all the other cases.
i am trying to write a function in lisp which have 2 parameters one function F and one list L
if i place '> in place of F and list L is '(1 2 3 4 5) it will return 5 as 5 is biggest.
and if we put '< then it compares all list elements and gives the smallest one as output.
and so on.
we can even put custom written function in place of F for comparison.
i wish i could provide more sample code but i am really stuck at the start.
(DEFUN givex (F L)
(cond
(F (car L) (car (cdr L))
;after this i got stuck
)
)
another attemp to write this function
(defun best(F list)
(if (null (rest list)) (first list)
(funcall F (first List) (best (F list)))))
You are almost there, just the else clause returns the f's return value instead of the the best element:
(defun best (F list)
(let ((first (first list))
(rest (rest list)))
(if (null rest)
first
(let ((best (best f rest)))
(if (funcall F first best)
best
first)))))
Examples:
(best #'< '(1 2 3))
==> 3
(best #'> '(1 2 3))
==> 1
Note that this recursive implementation is not tail-recursive, so it is not the most efficient one. You might prefer this instead:
(defun best (f list)
(reduce (lambda (a b) (if (funcall f a b) b a)) list))
Or, better yet,
(defmacro fmax (f)
`(lambda (a b) (if (,f a b) b a)))
(reduce (fmax <) '(1 2 3))
==> 1
(reduce (fmax >) '(1 -2 3 -4) :key #'abs)
==> 1
(reduce (fmax <) '(1 -2 3 -4) :key #'abs)
==> 4
How would I recurse through nested lists?
For example, given: '((A 1 2) (B 3 4))
How would I add 2 to the second element in each nested sublist?
(defun get-p0 (points)
(loop for x from 0 to
(- (list-length points) 1) do
(+ 2 (cadr (nth x points)))
)
)
I'm not really sure why (get-p0 '((A 1 2) (B 3 4))) returns NIL.
I'd go with something like this:
(loop for (letter x y) in '((A 1 2) (B 3 4))
collect (list letter (+ 2 x) y))
The reason: it's shorter and you don't measure the length of the list in order to iterate over it (why would you do that?)
Since you ask for a recursive solution:
(defun get-p0 (lst &optional (n 0))
(if (null lst)
nil
(let ((elt1 (first lst)) (eltn (cdr lst)))
(if (listp elt1)
(cons (get-p0 elt1) (get-p0 eltn))
(cons (if (= n 1) (+ elt1 2) elt1) (get-p0 eltn (+ n 1)))))))
so
? (get-p0 '((A 1 2) (B 3 4)))
((A 3 2) (B 5 4))
and it recurses further down if necessary:
? (get-p0 '((A 0 2) ((B -4 4) (C 10 4))))
((A 2 2) ((B -2 4) (C 12 4)))
The way you put it, you can consider the problem as a basic recursion pattern: you go through a list using recursion or iteration (mapcar, reduce, etc.; dolist, loop, etc.) and apply a function to its entries. Here is a functional solution:
(defun get-p0 (points)
(mapcar #'add-2 points))
where the auxiliary function can be defined as follows:
(defun add-2 (lst)
"Add 2 to the 2nd item"
(let ((res '()))
(do ((l lst (cdr l))
(i 1 (1+ i)))
((null l) (nreverse res))
(push (if (= 2 i)
(+ 2 (car l))
(car l))
res))))
As written your 'loop' use does not return anything; thus NIL is returned. As is your code is simply iterating over x and computing something; that something isn't stored anywhere.
So, how to get your desired result? Assuming you are willing to modify each point in points, this should work:
(defun get-p0 (points)
(loop for x from 0 to (- (list-length points) 1) do
(let ((point (nth x points)))
(setf (cadr point) (+ 2 (cadr point)))))
points)