Get element from list of list in lisp - lisp

I am a beginner with lisp.
I manipulate list of list:
((name1, second) (name2, second2))
The goal of my function is to get the second element of the list that have name as it first node.
For example:
my list is: ((name1, second1) (name2, second2))
getelement list name1 should return second1.
(defun getelement (list name)
(if (eq list '())
(if (string= (caar list) name)
(car (car (cdr list)))
(getelement (cdr list) name)
)
()
)
)
But I get this error. I really don't understand what is happening with my code. I tried to put ' before expressions...
Error: The variable LIST is unbound.
Fast links are on: do (si::use-fast-links nil) for debugging
Error signalled by IF.
Backtrace: IF

The if clauses are in the wrong order.
When the string matches, you are taking the next element (cdr) instead of that matching element (car)
This should work:
(defun getelement (list name)
(if (eq list '()) ;end of list,...
'() ;return empty list
(if (string= (caar list) name) ;matches,
(car (car list)) ;take the matching element
(getelement (cdr list) name))))

(defun get-element (list name)
(cadr (assoc name list :test #'string=)))

Related

Alternating upcase/downcase for a string in Common Lisp

I want to write a function that will return a string formatted with alternative upcase/downcase in Common Lisp. For example, entering "stackoverflow" should return the string "StAcKoVeRfLoW". Here's my attempt, but it just returns a list of cons pairs. Am I on the right track?
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil) nil
(coerce (cons
(cons (char-upcase (car lst)) (char-downcase (cadr lst)))
(mockify (cddr lst)))
'string))))
CL-USER> (mockify "meow")
((#\M . #\e) (#\O . #\w))
Using MAP: we are creating a new string, moving over the original string and upcase/downcase based on an alternating boolean variable.
CL-USER 353 > (let ((string "stackoverflow")
(upcase t))
(map (type-of string)
(lambda (element)
(prog1 (if upcase
(char-upcase element)
(char-downcase element))
(setf upcase (not upcase))))
string))
"StAcKoVeRfLoW"
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil)
;; return nil
nil
;; return a string (coerce)
(coerce
;; a list whose elements are cons-cells, but ...
(cons (cons (char-upcase (car lst))
(char-downcase (cadr lst)))
;; ... the rest is computed by calling mockify,
;; which returns either an empty list or a string
(mockify (cddr lst)))
'string))))
The types of your expressions are confusing, and in fact your example leads to an error when using SBCL:
> (mockify "meow")
The value
(#\O . #\w)
is not of type
CHARACTER
when setting an element of (ARRAY CHARACTER)
[Condition of type TYPE-ERROR]
Also, you are going to have to handle corner cases in your code, because as is, it is possible that (cadr list), i.e. (second list), is called on a list that has only one element. Then, the result would be NIL and char-downcase would fail with an error.
Using only strings
I'd suggest writing a version of the function that does not use intermediate lists:
let R be the string-downcase of the whole string
then modify every other character of R by upcasing it
So for example, one way to do it (among others) would be:
(defun mockify (chars)
(let ((chars (string-downcase chars)))
(prog1 chars
(upcasify chars 0))))
(defun upcasify (string index)
(when (< index (length string))
(setf (char string index) (char-upcase (char string index)))
(upcasify string (+ index 2))))
Using only lists
If you prefer having a recursive function that processes lists, I'd rather define it in layers:
coerce string to list
process the list recursively
eventually, coerce the resulting list back to a string
This will avoid doing conversions from strings to lists at every step, and make the code simpler at each level.
(defun mockify (chars)
(coerce (mockify-list (coerce chars 'list)) 'string))
(defun mockify-list (chars)
...)
The list version is recursive and look like what you tried to do, but take care of corner cases.
There is more than one way to do it. Here is a loop based solution:
(let ((string "StackOverflow"))
(with-output-to-string (s)
(loop :for c :across string
:for up := t :then (not up)
:do (princ (if up
(char-upcase c)
(char-downcase c))
s))))
Fun thing - I actually wrote a similar thing some time ago.
https://github.com/phoe/string-pokemonize

How can I return symbols based on the sum of lists?

So I am new to Scheme and have encountered a problem. What I am trying to do is the following. It's a rather simple problem nevertheless I am receiving several errors:
I try to sum up the elements of lists (which only consists of numbers). If the total amount is even, the procedure should return <'divisible_by_2>.
If the total amount is odd, it should return <'not_divisible_by_2>.
The initial sstep was to build a procedure that sums up the lists. This one works. The second step was to build an if function which takes the sum of lists and returns <'divisible_by_2> if the sum is even and <'not_divisible_by_2> if it is odd.
What I wrote so far:
(define (divisible_or_not list-sum lst)
(if (odd? list-sum lst)
(lambda (list-sum lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(list-sum (car lst)) (list-sum (cdr lst)))
(else
(+ (car lst) (list-sum (cdr lst)))
)
)
)
('divisible_by_2)
('not_divisible_by_2)
)
)
)
Version 2.0 (lst=tree; tree-count=sum-lst):
(define (divisible-or-not tree)
(define (tree-count tree)
(cond
((null? tree)
0)
((pair? (car tree))
(+(tree-count (car tree)) (tree-count (cdr tree)))
(else
(+ (car tree) (tree-count (cdr tree))))))
(if (odd? tree-count tree)
('divisible-by-2)
('not-divisible-by-2))))
Your code, properly indented, looks like so:
(define (divisible_or_not list-sum lst)
(if (odd? list-sum lst)
(lambda (list-sum lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(list-sum (car lst)) (list-sum (cdr lst)))
(else
(+ (car lst) (list-sum (cdr lst))))))
('divisible_by_2)
('not_divisible_by_2))))
The structure of your program looks like this:
(if ...
(lambda (...) ...))
In other words, if your test succeeds, you return an anonymous function, and if the test fails, you return nothing (in Scheme, the value is undefined in that case).
Inside your lambda, the code is a list of three expressions, a cond, the form ('divisible_by_2) and the form ('not_divisible_by_2).
First of all, do not use underscores for separating words in Lisp/Scheme, use dashes, like so: divisible-by-2.
Secondly, only the last expression's value is returned from the lambda, so the intermediate cond, since it has no side-effect, is basically doing work for nothing. The second form, ('divisible_by_2), looks like a function call but is going to give you an error. If you want to return a symbol, just quote it, without parentheses: 'divisible-by-2.
Since you already have an intermediate function, you can associate it to a name:
(define tree-count (sum tree)
(cond ...))
I named it tree-count because you also recurse into the car of your lists.
Once you have this function, you only need to apply it:
(if (even? (tree-count tree))
'divisible-by-2
'not-divisible-by-2)

Returning NIL from a recursion in Lisp

I'm working on a problem in a book where I have a binary tree and I need to check if the sum of all the atoms on the left and right subtree are equal and if they're not, return nil. I managed to do it in two functions but when I try to do it in one I get an error because it tries to add a number to nil.
The code is
(defun foo (list)
(cond ((null list) 0)
((atom list) list)
((/= (foo (cadr list))
(foo (caddr list))) nil)
( T (+ (foo (car list))
(foo (cdr list))))))
edit: the problem was two fold.
1) with the previous structure it would try to evaluate (cdr '(number)) so it would return null when it hit a list that looked like '(a (b c) d) since it would try to access (cdr '(d))
2) i used /= which only works if both arguments are numbers
The code that worked:
(defun foo (list)
(cond ((null list) 0)
((atom list) list)
((null (cdr list)) (car list))
((null (equal(foo (cadr list)) (foo (caddr list)))) nil)
(T (+ (car list)
(foo (cadr list))
(foo (caddr list))))))
After having defined how you represent a binary tree, I mean the right subtree could be the cdr or the cadr, I would separate the two problems:
(defun sum-of-subtree (tree)
(cond ((null tree) 0)
((atom tree) tree)
(t (+ (sum-of-subtree (car tree))
(sum-of-subtree (cdr tree))))))
(defun foo (tree)
(cond ((null tree) t) ;or whatever you want
((atom tree) t)
((= (sum-of-subtree (car tree))
(sum-of-subtree (cdr tree))) t)
(t nil)))
Like that, you will not be confusing the value of the sum of the subtree with the comparison. Other languages have stronger typing, which avoids mixing the purposes of different functions
Note: I'm assuming your binary trees are lists of (val left-sub right-sub), which seems to match your code.
I'm not sure that there's a clean way to do that with recursion and a single function, since the recursive process (summing the left and right subtrees) is different from the value your function needs to return (whether or not the left and right subtrees are equal).
However, if you absolutely have to solve it with one function, you could cheat a little. I see two options:
Option 1
Local function
(defun foo (list)
(labels ((sum-subtrees (list)
(cond
((null list) 0)
((atom list) list)
(t (+ (car list)
(sum-subtrees (cadr list))
(sum-subtrees (caddr list)))))))
(= (sum-subtrees (cadr list))
(sum-subtrees (caddr list)))))
This works by defining a local function to handle the recursive bit- #'sum-subtrees- and then just relies on that to compute the final output.
Option 2
Multiple value return
(defun foo (list)
(cond
((null list) (values t 0))
((atom list) (values t list))
(t (let ((left-sub (nth-value 1 (foo (cadr list))))
(right-sub (nth-value 1 (foo (caddr list)))))
(values (= left-sub right-sub)
(+ (car list)
left-sub
right-sub))))))
This solution exploits how common lisp functions can return multiple values. Basically, the function returns both the original condition (= left-subtree right-subtree) and the sum of the tree. Any other code which is expecting just a single value will get the first return value (the condition), so any code that would use this function should not notice the extra return value, but the data is there if you ask for it.
The way we return multiple values is with the values function. In this code, for example, we return (values t 0) in the case of list being nil to indicate that its "left and right subtrees" are equal and its sum is 0, and
(values (= left-sub right-sub)
(+ (car list)
left-sub
right-sub))
to produce the recursive return value.
There are a few ways to get access to the extra return values, but the one used here is #'nth-value, which returns the nth value returned instead of the first. That's why, when we make the recursive call to compute the size of the subtree, we use (nth-value 1 (foo <subtree>)).
NOTE: Please never actually use that solution for this- multiple value return is very useful and powerful, but in this case it is more confusing than it's really worth.
The code that worked:
(defun foo (list)
(cond ((null list) 0)
((atom list) list)
((null (cdr list)) (car list))
((null (equal(foo (cadr list)) (foo (caddr list)))) nil)
(T (+ (car list)
(foo (cadr list))
(foo (caddr list))))))

creating assoc function in lisp that will find value from a-list

How can i create an assoc function that can find value from a-list.
Can anyone help me on this as i don't know how it works and am new to lisp.
Could you describe in steps.
I have already googled about it but couldnot find anything on creating the assoc function.
The most basic lisp operations are list eaters:
(defun some-function (list-to-consume perhaps-additional-args)
(cond ((endp list-to-consume) <end-of-list-expression>)
((<predicate> list-to-consume perhaps-additional-args)
<result-expression>)
(t (some-function (cdr list-to-consume) perhaps-additional-args))))
Examples:
;; The predicate is the endp expression
(defun mylength (list &optional (len 0))
(cond ((endp list) len)
(t (mylength (cdr list) (1+ len)))))
;; A member function
(defun mymember (element list)
(cond ((endp list) nil)
((equal (car list) element) list)
(t (mymember element (cdr list)))))
;; Exchange an element with another in a list
;; notice how this builds up a list recursively
(defun exchange (list element replacement)
(cond ((endp list) nil)
((equal (car list) element) (cons replacement (exchange (cdr list) element replacement)))
(t (cons (car list) (exchange (cdr list) element replacement)))))
There are other more advanced ways to replace most list eaters with loop or higher order functions like mapcar, map and reduce, but if you are learning LISP you probably should be familiar with the list eaters first.

Searching lists that contain lists or conses

Lets say that we got a list like this(with much more elements but the method should be the same):
(define l '((cons 'name 'john)
(cons 'sur 'asurname)
(cons 'name 'george)
(cons 'sur 'georgesurname)))
and we can always add more elements to the existing list. Which is the most effective way lets say to write a function that takes the name of a the user and returns the surname:
something like :
(define display-surname
(lamdba (name)
(...)))
What is the general practice in such cases? Can anyone point an example/link of a how to?
It'd be a better idea to represent each record (name,surname) in a single list, and then handle your data as a list of lists of pairs:
(define lst '(((name . a) (sur . b)) ((name . c) (sur . d))))
With the above representation, finding a name (given a surname) is as simple as this (assuming that each field in the record is always found in the same position):
(define display-surname
(lambda (lst name)
(cond ((null? lst) #f)
((eq? (cdaar lst) name) (cdadar lst))
(else (display-surname (cdr lst) name)))))
You can simplify things even further (again assuming that each field in the record is always in the same position) by representing the above data as follows, with the corresponding changes in display-surname:
(define lst '((a . b) (c . d)))
(define display-surname
(lambda (lst name)
(cond ((null? lst) #f)
((eq? (caar lst) name) (cdar lst))
(else (display-surname (cdr lst) name)))))
Either way, this works:
(display-surname lst 'a)
> 'b
(display-surname lst 'x)
> #f