appending a variable to list of lists using lisp - list

I have a list defined as follows:
(defparameter testlist '(((a b) (c d)) ((e f) (g h ))) )
I also have a variable defined as :
(defparameter feature 'u)
I want to append a feature to (c d).
When I try:
(setf (nth 1 (nth 0 testlist)) (append (nth 1 (nth 0 testlist)) feature))
testlist becomes:
(((A B) (C D . U)) ((E F) (G H)))
However, I want a non dotted list.
I can't figure out why I have this result. Can you explain why or suggest a better method to append, that is comprehensible for a beginner level?

First off your feature is not a list. append allows the last argument to be anything but then the result would not be a proper list if the last element is itself not a proper list. Thus:
(append '(1 2) 3) ; ==> (1 2 . 3)
(append '(1 2) '(3 . 4)) ; ==> (1 2 3 . 4)
(append '(1 2) '(3 4)) ; ==> (1 2 3 4)
Thus you need to append (list feature) if you want feature to be one element in the list you are replacing and not the new dotted value.
You need to locate the list you are changing and everything before you need to recreate but everything after you can just share with the original source:
Looking at your structure you want to change the cadar while you need to recreate the caar while the result can share the cdr:
(let ((lst '(((a b) (c d)) ((e f) (g h )))) (feature 'x))
(list* (list (caar lst) (append (cadar lst) (list feature))) (cdr lst)))
; ==> (((a b) (c d x)) ((e f) (g h)))
Now how you choose to use that result is up to you. You can setf the binding and you will have the same behaviour as if you mutated except for the unwanted consequences.

Related

Using nested car with cons in a lisp function

I'm making a recursive lisp function that takes two lists and makes a sublist of index pairs
ex: put in (A B C D) and (1 2 3 4) and get ((1 A) (2 B) (3 C) (4 D))
However, I'm having trouble using car along with cons to make said sublist. Here's my code:
(DEFUN zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
(setq c NIL)
(progn (zipper (cdr a) (cdr b))
(cons '((car a) (car b)) c))
)
)
I played around for a little and it appears using car to create lists just doesn't work most of the time. Additionally, I'm using CLISP. Any ideas?
Thanks!
The general idea goes into the right direction. There are a bunch of problems, though. Let's have a look.
(DEFUN zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
(setq c NIL)
(progn (zipper (cdr a) (cdr b))
(cons '((car a) (car b)) c))
)
)
First indentation:
(DEFUN zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
(setq c NIL)
(progn (zipper (cdr a) (cdr b))
(cons '((car a) (car b)) c)) ; <--
)
)
Next dangling parentheses:
(DEFUN zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
(setq c NIL)
(progn (zipper (cdr a) (cdr b))
(cons '((car a) (car b)) c))))
Return the empty list in IF for the true case:
(defun zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
nil
(progn (zipper (cdr a) (cdr b))
(cons '((car a) (car b)) c))))
Now cons to the result in the false case:
(defun zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
nil
(cons '((car a) (car b))
(zipper (cdr a) (cdr b)))))
What remains to be done?
see the comment by 'rsm': replace the quote with a call to list.
don't use list-length. Use null instead. It checks if a list is empty. list-length would traverse the input whole lists on each call -> inefficient.
If you call list-length at each step of recursion, you are going to traverse both lists entirely each time, which gives your zipper function a quadratic time complexity with respect to the sum of your lists' sizes:
(zipper '(1 2 3) '(4 5 6))
=> (list-length (1 2 3))
=> (list-length (2 3))
=> (list-length (3))
=> (list-length ())
=> (list-length (4 5 6))
=> (list-length (4 5))
=> (list-length (5))
=> (list-length ())
(zipper '(2 3) '(5 6))
=> (list-length (2 3))
...
=> (list-length (5 6))
...
...
This is inefficient and not necessary here. Since you are already visiting both lists, you can directly check if any of them is empty using null or endp, which take constant time. You return NIL as soon as one of the list is empty, which is by the way the default behaviour of mapcar. Notice also that mapcar can work on multiple lists at the same time, for example:
(mapcar #'+ '(1 2) '(5 8))
=> (6 10)
If you know a function that takes (at least) two arguments and return a list, then you could mapcar that function over your lists and have a list of lists.
The zip function from other languages such as Python and Haskell is a special case of mapcar.
The traditional zip function can be achieved via:
> (mapcar #'list list1 list2 ... listn)
Such that for this case:
> (mapcar #'list '(A B C D) '(1 2 3 4))
((A 1) (B 2) (C 3) (D 4))
To swap the order of the pairs as you indicated, simply change the function passed to mapcar accordingly:
> (mapcar #'(lambda (x y) (list y x)) '(A B C D) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))
Checkout the documentation for mapcar for more details.
zip function with arbitrary number of lists
(defun zip (&rest lists)
(apply #'mapcar #'list lists))
Shortest list determines depth of zipping.
CL-USER> (zip '(1 2 3) '(a b c) '("a" "b" "c"))
((1 A "a") (2 B "b") (3 C "c"))
CL-USER> (zip '(1 2 3) '(a b c) '("a" "b" "c" "d"))
((1 A "a") (2 B "b") (3 C "c"))
You could do something such as this:
(defun zipper (a b)
(if (or (null a) (null b))
nil
(cons (list (car b) (car a)) (our-combiner (cdr a) (cdr b)))))
We can check if either of the lists is null, so that we could stop when one of the lists runs out (similar to how mapcar will stop applying a function to lists when one of the lists runs out). We can then cons a nested list with the car's of the lists in each recursive call. Your output would be:
CL-USER> (zipper '(a b c d) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))
CL-USER>
We could also use mapcar as it will iterate over both lists and returns the result of applying the function to both lists (unlike mapc). This is fewer lines of code, and since it will return when some list runs out, there's no need for a conditional:
(defun zipper (a b)
(mapcar #'list b a))

Function in lisp that displays a list in a specific way

I need to make a function in lisp that displays a list like this:
(a b (c d) (e f g) h) ->
(a
b
(c
d)
(e
f
g)
h)
So far i managed to make a function that displays a list like this.
(defun print1-lista(l)
(princ pard)
(do ((lst l (cdr lst)))
((null (cdr lst)) (princ (car lst)) (princ par))
(princ (car lst))
(terpri)))
PRINT1-LISTA
> (print1-lista '(1 (1 2) 3 4))
{1
(1 2)
3
4}
}
In Common Lisp, you can customize the printer in many ways. For instance, the variables *print-case* and *print-margin-right* will control the case that symbols are printed in, and the right margin as used by the pretty printer. Thus you can do something like this:
(let ((*print-case* :downcase)
(*print-right-margin* 2))
(pprint '(a b (c d) (e f g) h)))
to get output like this:
(a
b
(c
d)
(e
f
g)
h)
Here is a quick and dirty sketch of such a scheme for pretty printing in PLT-Scheme
(define (deep-ppr lst depth)
(let ((elt (car lst)))
(if (list? elt)
(begin
(printf "~a(~a\n" (make-string depth #\ ) (car elt))
(deep-ppr (cdr elt) (+ 1 depth)))
;; not a list
(begin
(printf "~a~a" (make-string depth #\ ) elt)))
(if (empty? (cdr lst)) (printf ")")
(begin
(printf "\n")
(deep-ppr (cdr lst) depth)))))
Which yields this. You can change the scheme for introducing newlines however you'd like.
sicp.rkt> (deep-pp '(1 (1 2 4) 3 4 5 6 (1 2 3 5) 7) 0)
(1
(1
2
4)
3
4
5
6
(1
2
3
5)
7)

implement equal function to recursion function

I want to fix my own function that gives the same result with the default intersection function. I've been trying to write a lisp code which prints same elements in the two lists. My code works for it. But it doesn't work for nested lists. How can I fix this?
(defun printelems (L1 L2)
(cond
((null L1) nil) ((member (first L1) L2) (cons (first L1) (printelems (rest L1) L2)))
(t (printelems (rest L1) L2))))
Expected inputs and outputs
(printelems '(2 3 5 7) '( 2 3)) => It works
=> (2 3)
(printelems '(a b '(c f)) '(a d '(c f) e)) => It doesn't work.
=> (a (c f))
Edit
Using the default intersection function works as intended. How can I use the equal function in my recursive function?
For default intersection,
(intersection '(a b (c f)) '(a d (c f) e) :test 'equal)
((C F) A)
(intersection '(a b (c f)) '(a d c f e) :test 'equal)
(A)
My intersection,
(printelems '(a b (c f)) '(a d c f e))
(A C F)
(printelems '(a b (c f)) '(a d (c f) e) )
(A C F)
My edited code:
(defun flatten (l)
(cond ((null l) nil)
((atom (car l)) (cons (car l) (flatten (cdr l))))
(t (append (flatten (car l)) (flatten (cdr l))))))
(defun printelemsv1(list1 list2)
(cond
((null list1) nil)
(((member (first list1) list2) (cons (first list1) (printelemsv1 (rest list1) list2)))
(t (printelemsv1 (rest list1) list2)))))
(defun printelems (L1 L2)
(printelemsv1 (flatten L1) (flatten L2)))
Common Lisp already has an intersection function. If you want to compare sublists like (C F), you'll want to use equal or equalp as the test argument.
(intersection '(a b '(c f)) '(a d '(c f) e) :test 'equal)
;=> ('(C F) A)
While it doesn't change how intersection works, you probably don't really want quote inside your list. Quote isn't a list creation operator; it's a "return whatever the reader read" operator. The reader can read (a b (c f)) as a list of two symbols and a sublist, so (quote (a b (c f))), usually abbreviated as '(a b (c f)) is fine. E.g.:
(intersection '(a b (c f)) '(a d (c f) e) :test 'equal)
;=> ((C F) A)
It's always helpful when you provide an example of input and the expected output. I assume you mean you have two lists like '(1 (2 3) 4) and '((1) 2 5 6) that the function should produce '(1 2). In this case you can just flatten the two lists before giving them to printelems.
Since I'm not familiar with Common-Lisp itself I will leave you with one example and a link.
(defun flatten (structure)
(cond ((null structure) nil)
((atom structure) (list structure))
(t (mapcan #'flatten structure))))
Flatten a list - Rosetta Code
flatten takes an arbitrary s-expression like a nested list '(1 (2 3) 4) and returns '(1 2 3 4).
So now you just have to write a new function in which you use your printelems as a helper function and give it flattened lists.
(defun printelems.v2 (L1 L2)
(printelems (flatten L1) (flatten L2)))
Take this with a grain of salt, since as said before I'm not familiar with Common-Lisp, so appologies in advance for any potential syntax errors.

Recursive split-list function LISP

The split-list function takes a list and returns a list of two lists consisting of alternating elements of the input. I wrote the following:
(defun split-list (L)
(cond
((endp L) (list NIL NIL))
(t (let ((X (split-list (cdr L))))
(cond
((oddp (length L))
(list (cons (first L) (first X)) (cadr X)))
(t (list (first X) (cons (first L) (cadr X)))))))))
The output is as expected for odd numbered lists, the first list consisting of the 1st, 3rd, 5th etc elements and the second part consisting of the 2nd, 4th, 6th etc. With an even list however, the 1st, 2nd ,3rd.. are on the right of the returned lists with the rest on the left.
For Example:
(SPLIT-LIST '(a b c 1 2 3))
(SPLIT-LIST RETURNED ((b 1 3) (a c 2))
the order should be swapped. Is there a major flaw in my logic that I'm missing? Can I rectify this situation without making major alterations?
Yes, you can rectify the problem without major modifications.
Add a case for (endp (cdr L))
Do the recursive call on cddr L
After that, the else case will always have two new elements, one to cons onto each list; there is no more need for the length call
First, when you have cond with only one test and a default t clause, please use if instead.
Also, you are using first, but cadr; second is more readable in your context than cadr.
Now, the order is swapped for even lists. Try to perform a step-by-step execution. It might be a little tedious by hand but this is useful to understand what happens. I personally prefer to use the trace macro: (trace split-list). Then, running your example:
0: (split-list (a b c 1 2 3))
1: (split-list (b c 1 2 3))
2: (split-list (c 1 2 3))
3: (split-list (1 2 3))
4: (split-list (2 3))
5: (split-list (3))
6: (split-list nil)
6: split-list returned (nil nil)
5: split-list returned ((3) nil)
4: split-list returned ((3) (2))
3: split-list returned ((1 3) (2))
2: split-list returned ((1 3) (c 2))
1: split-list returned ((b 1 3) (c 2))
0: split-list returned ((b 1 3) (a c 2))
Unclear? Try with an odd-sized list:
0: (split-list (a b c 1 2))
1: (split-list (b c 1 2))
2: (split-list (c 1 2))
3: (split-list (1 2))
4: (split-list (2))
5: (split-list nil)
5: split-list returned (nil nil)
4: split-list returned ((2) nil)
3: split-list returned ((2) (1))
2: split-list returned ((c 2) (1))
1: split-list returned ((c 2) (b 1))
0: split-list returned ((a c 2) (b 1))
It seems you always store the innermost result in the left list!
A possible recursive implementation goes roughly like this:
(defun split-list (list)
(if (endp list)
'(nil nil)
(destructuring-bind (left right) (split-list (cddr list))
(list (cons (first list) left)
(if (second list)
(cons (second list) right)
right)))))
But this can blow the stack for sufficiently large inputs. For your information, here is a simple non-recursive approach with loop:
(defun split-list (list)
(loop for (a b) on list by #'cddr
collect a into left
when b
collect b into right
finally (return (list left right)))
And since you probably will have to split your list into more than 2 lists in your next assignment, a more generic version, still with loop:
(defun split-list (list &optional (n 2))
(loop with a = (make-array n :initial-element nil)
for e in list
for c = 0 then (mod (1+ c) n)
do (push e (aref a c))
finally (return (map 'list #'nreverse a))))
(split-list '(a b c d e f g) 3)
=> ((a d g) (b e) (c f))
If you want to have fun with circular lists, you can also try this, which works for any sequence, not only lists:
(defun split-n (sequence &optional (n 2))
(let* ((ring (make-list n :initial-element nil))
(head ring)
(last (last ring)))
(setf (cdr last) ring)
(map nil
(lambda (u)
(push u (first ring))
(pop ring))
sequence)
(setf (cdr last) nil)
(map-into head #'nreverse head)))
If you plan to investigate how this works, evaluate (setf *print-circle* t) first.
One of the very common idioms in recursive list processing is to build up result lists in reverse order, and then to reverse them just before returning them. That idiom can be useful here. The essence of your task is to return a list of two lists, the first of which should contain even-indexed elements, the second of which should contain odd-indexed elements. Here's how I'd approach this problem (if I were doing it recursively). The idea is to maintain a list of even elements and odd elements, and a boolean indicating whether we're at an even or odd position in the overall list. On each recursion, we add an element to the "evens" list, since the current index of the current list is always zero, which is always even. The trick is that on each recursive call, we swap the evens and the odds, and we negate the boolean. At the end, we use that boolean to decide which lists are the "real" evens ands odds list.
(defun split-list (list &optional (evens '()) (odds '()) (evenp t))
"Returns a list of two lists, the even indexed elements from LIST
and the odd indexed elements LIST."
(if (endp list)
;; If we're at the end of the list, then it's time to reverse
;; the two lists that we've been building up. Then, if we ended
;; at an even position, we can simply return (EVENS ODDS), but
;; if we ended at an odd position, we return (ODDS EVENS).
(let ((odds (nreverse odds))
(evens (nreverse evens)))
(if evenp
(list evens odds)
(list odds evens)))
;; If we're not at the end of the list, then we add the first
;; element of LIST to EVENS, but in the recursive call, we swap
;; the position of EVENS and ODDS, and we flip the EVENP bit.
(split-list (rest list)
odds
(list* (first list) evens)
(not evenp))))
CL-USER> (split-list '())
(NIL NIL)
CL-USER> (split-list '(1))
((1) NIL)
CL-USER> (split-list '(1 2))
((1) (2))
CL-USER> (split-list '(1 2 3))
((1 3) (2))
CL-USER> (split-list '(1 2 3 4))
((1 3) (2 4))
CL-USER> (split-list '(1 2 3 4 5 6 7 8 9 10))
((1 3 5 7 9) (2 4 6 8 10))
Recursion is always a good idea, as a conceptual tool aiding our thinking while developing a problem's solution. Once the correct code is formulated, iff your language is limited in its handling of recursion, re-write it to use other means.
A modern implementation of a Scheme-derived language (Scheme is a kind of a Lisp, right?), Racket has unlimited recursion, implementing call stack on the heap. As such, recursive code for a recursive algorithm is perfectly fine.
Correctness / serenity simplicity first, efficiency later!
The simple solution for your requirements is (in the executable "pseudocode" of Haskell)
foldr (\x [a, b] -> [x:b, a]) [[], []]
I first saw this neat trick in an old F# (IIRC) answer by user ed'ka (IIRC); quite a few years back. (But actually it appears to have been in haskellwiki since more or less forever).
Coded in direct recursive style in Scheme, it is
(define (split xs)
(cond
((null? xs) (list '() '()))
((split (cdr xs)) => (lambda (acc)
(list (cons (car xs) (cadr acc)) ; always in the first subgroup!
(car acc))))))
The list's head element must appear in the first subgroup. No need to exert ourselves trying hard to arrange for it to happen, just say it, and it happens just because you said so, all by itself, because of the magic that is recursion&hairsp;!
(split '(a b c 1 2 3))
(split '(a b c 1 2))
; '((a c 2) (b 1 3))
; '((a c 2) (b 1))
A side note: I decided to never use if again, in preference of cond, because an if's clause in itself says nothing about its activation conditions - we must count, of all things, to know which is which. With cond it's plain, and it is right there at the clause's start.
It is easy enough to amend this to produce e.g. a three-way split, with
(define (split3 xs)
(cond
((null? xs) (list '() '() '()))
(else (apply
(lambda (a b c) ; Scheme-style destructuring
(list (cons (car xs) c) ; rotate right:
a ; xs's 2nd elt to appear in the 2nd group!
b)) ; head element of (cdr xs) is in `a`
(split3 (cdr xs)))))) ; the recursive result
(split3 '(a b c 1 2 3))
(split3 '(a b c 1 2))
; '((a 1) (b 2) (c 3))
; '((a 1) (b 2) (c))

Combining list of list

Hello i have to programm this fucntion in lisp:
(defun combine-list-of-lsts (lst)...)
So when executing the function i should get
(combine-list-of-lsts '((a b c) (+-) (1 2 3 4)))
((A + 1) (A + 2) (A + 3) (A + 4) (A-1) (A-2) (A-3) (A-4) (B + 1) (B + 2) (B + 3) (B + 4) (B-1) (B-2) (B-3) (B-4)(C + 1) (C + 2) (C + 3) (C + 4) (C-1) (C-2) (C-3) (C-4))
What i have now is:
(defun combine-list-of-lsts (lst)
(if (null (cdr lst))
(car lst)
(if (null (cddr lst))
(combine-lst-lst (car lst) (cadr lst))
(combine-lst-lst (car lst) (combine-list-of-lsts (cdr lst))))))
Using this auxiliar functions:
(defun combine-lst-lst (lst1 lst2)
(mapcan #'(lambda (x) (combine-elt-lst x lst2)) lst1))
(defun combine-elt-lst (elt lst)
(mapcar #'(lambda (x) (list elt x)) lst))
But what i get with this:
((A (+ 1)) (A (+ 2)) (A (+ 3)) (A (+ 4)) (A(-1)) (A(-2)) (A(-3)) (A(-4))...)
I dont know how to make this but without the parenthesis
The first thing is to look at this case:
(combine-list-of-lsts '((a b c)))
What should that be? Maybe not what your function returns...
Then I would look at the function combine-list-of-lsts. Do you need two IF statements?
Then look at combine-elt-lst. Do you really want to use LIST? It creates a new list. Wouldn't it make more sense to just add the element to the front?
Usually, when you want to reduce mutliple arguments into single result, you need function #'reduce. Your combination of lists has name cartesian n-ary product.
Following function:
(defun cartesian (lst1 lst2)
(let (acc)
(dolist (v1 lst1 acc)
(dolist (v2 lst2)
(push (cons v1 v2) acc)))))
creates cartesian product of two supplied lists as list of conses, where #'car is an element of lst1, and #'cdr is an element of lst2.
(cartesian '(1 2 3) '(- +))
==> ((3 . -) (3 . +) (2 . -) (2 . +) (1 . -) (1 . +))
Note, however, that calling #'cartesian on such product will return malformed result - cons of cons and element:
(cartesian (cartesian '(1 2) '(+ -)) '(a))
==> (((1 . +) . A) ((1 . -) . A) ((2 . +) . A) ((2 . -) . A))
This happens, because members of the first set are conses, not atoms. On the other hand, lists are composed of conses, and if we reverse order of creating products, we could get closer to flat list, what is our goal:
(cartesian '(1 2)
(cartesian '(+ -) '(a)))
==> ((2 + . A) (2 - . A) (1 + . A) (1 - . A))
To create proper list, we only need to cons each product with nil - in other words to create another product.
(cartesian '(1 2)
(cartesian '(+ -)
(cartesian '(a) '(nil))))
==> ((2 + A) (2 - A) (1 + A) (1 - A))
Wrapping everything up: you need to create cartesian product of successive lists in reversed order, having last being '(nil), what can be achieved with reduce expression. Final code will look something like this:
(defun cartesian (lst1 lst2)
(let (acc)
(dolist (v1 lst1 acc)
(dolist (v2 lst2)
(push (cons v1 v2) acc)))))
(defun combine-lsts (lsts)
(reduce
#'cartesian
lsts
:from-end t
:initial-value '(nil)))
There is one more way you can try,
(defun mingle (x y)
(let ((temp nil))
(loop for item in x do
(loop for it in y do
(cond ((listp it) (setf temp (cons (append (cons item 'nil) it) temp)))
(t (setf temp (cons (append (cons item 'nil) (cons it 'nil)) temp))))))
temp))
Usage:(mingle '(c d f) (mingle '(1 2 3) '(+ -))) =>
((F 1 +) (F 1 -) (F 2 +) (F 2 -) (F 3 +) (F 3 -) (D 1 +) (D 1 -) (D 2 +)
(D 2 -) (D 3 +) (D 3 -) (C 1 +) (C 1 -) (C 2 +) (C 2 -) (C 3 +) (C 3 -))