I need a function that will take in a list with words and split that list into two lists if at any point the word 'FOO' is found. I have come up with a recursive solution, may not be the best, but I am having a bit of trouble. I only need to pass 1 argument, the list to be analyzed, but I do not know how to build up the second list off to the side. Any suggestions? Thanks!
;Splits a list into 2 if the word 'FOO' is present
;----------------------------------------------------------------------
;LOAD FILE: (load "C:\\split.lisp")
;USAGE: (split '(with great power foo comes great responsibility) '())
;OUTPUT: ((with great power)(comes great responsibility))
(defun split (x y)
(cond
( ;IF: first element in list is nil
(EQ (car x) nil)
x ;RETURN the list
)
( ;ELSE IF: first element is 'FOO'
(EQ (car x) 'FOO)
(cons (reverse y ) (cons (cdr x) nil))
)
( ;ELSE: recursively call split but pass the rest of x and
;prepend y with the head of x
t
(split (cdr x) (cons (car x) y))
)
) ;END cond
) ;END split
The first test should be different.
The following is not a really good solution: it is not tail-recursive and it uses side-effects. But still...
(defun split (x)
(cond ((null x) x)
((eq (first x) 'foo)
(list nil (rest x)))
(t (let ((l (split (rest x))))
(push (first x) (first l))
l))))
Above uses the PUSH macro. One of the interesting facilities of Common Lisp is that you can use places to modify. In this cases we modify the first sublist of our list to be returned. We push the first element of the list onto the first sublist.
CL-USER 12 > (split '(1 2 3 foo a b c))
((1 2 3) (A B C))
In Common Lisp one would usually write a solution in a non-recursive fashion.
In your recursive version, the typical way to reduce a function to one argument is this: Write the function with one argument and this function then calls a helper function with two arguments. The helper function can also be locally defined using LABELS.
Here's my take on it, using nothing but lists:
(defun split (lst)
(labels ((split-rec (lst a)
(cond
((or (null lst)
(eq (car lst) 'foo))
(values (reverse a) (cdr lst)))
(t (split-rec (cdr lst) (cons (car lst) a))))))
(split-rec lst ())))
split offloads most of the work to split-rec (defined in the labels call), which recursively consumes the list of tokens, until it reaches the end of the list, or sees 'foo. At that point, it immediately takes the remainder of the list and treats that as the second list. Because the first list (a) is being built-up recursively, split-rec has to reverse it before returning it.
Here are a couple of runs through the REPL:
> (split '(with great power foo comes great responsibility))
(WITH GREAT POWER) ;
(COMES GREAT RESPONSIBILITY)
> (split '(with great power comes great responsibility))
(WITH GREAT POWER COMES GREAT RESPONSIBILITY) ;
NIL
> (split nil)
NIL ;
NIL
> (split '(with great power foo comes great foo responsibility) :on 'foo)
(COMES GREAT) ;
(WITH GREAT POWER RESPONSIBILITY)
> (split '(foo with great power comes great responsibility) :on 'foo)
NIL ;
(WITH GREAT POWER COMES GREAT RESPONSIBILITY)
Most of the edge cases that I could think up are handled, and two lists are always returned. Callers can use multiple-value-bind to get both lists out, i.e.:
(multiple-value-bind (a b)
(split '(with great power foo comes great responsibility))
; do something useful with a and b
)
(defun split (lst)
(let* ((a (make-array (length lst) :initial-contents lst))
(index (position 'foo a)))
(cond ((null index) a)
(t (cons (loop for i from 0 to (1- index)
collect (aref a i))
(list (loop for i from (1+ index) to (1- (length a))
collect (aref a i))))))))
Create an array from the list so that there elements are easier to access.
Check if foo exists, if it does mark the index
Use loop to create two lists, one of the elements before foo, and another one of the elements after foo, and cons them together.
Here I've also tried! :)
There's one thing you would want to clarify though: in corner cases like: foo is the first element of the list, should you return two lists or only the second one? If foo is the last element in the list, should you return list and nil or only the first list? If foo isn't in the list, should you return just the list, or list and nil / nil and list?
(defun split (list &key (on-symbol 'foo))
(let (result result-head)
(mapl
#'(lambda (a)
(if (eql (car a) on-symbol)
(return-from split
(if result
(values result (copy-list (cdr a)))
(copy-list (cdr a))))
(if result
(setf (cdr result-head) (list (car a))
result-head (cdr result-head))
(setf result (list (car a))
result-head result)))) list) result))
(split '(1 2 3 4 5 foo a b c))
(split '(foo 1 2 3 4 5 foo a b c))
(split '(1 2 3 4 5 a b c))
Related
I'm trying to reverse a list in Lisp, but I get the error: " Error: Exception C0000005 [flags 0] at 20303FF3
{Offset 25 inside #}
eax 108 ebx 200925CA ecx 200 edx 2EFDD4D
esp 2EFDCC8 ebp 2EFDCE0 esi 628 edi 628 "
My code is as follows:
(defun rev (l)
(cond
((null l) '())
(T (append (rev (cdr l)) (list (car l))))))
Can anyone tell me what am I doing wrong? Thanks in advance!
Your code as written is logically correct and produces the result that you'd want it to:
CL-USER> (defun rev (l)
(cond
((null l) '())
(T (append (rev (cdr l)) (list (car l))))))
REV
CL-USER> (rev '(1 2 3 4))
(4 3 2 1)
CL-USER> (rev '())
NIL
CL-USER> (rev '(1 2))
(2 1)
That said, there are some issues with it in terms of performance. The append function produces a copy of all but its final argument. E.g., when you do (append '(1 2) '(a b) '(3 4)), you're creating a four new cons cells, whose cars are 1, 2, a, and b. The cdr of the final one is the existing list (3 4). That's because the implementation of append is something like this:
(defun append (l1 l2)
(if (null l1)
l2
(cons (first l1)
(append (rest l1)
l2))))
That's not exactly Common Lisp's append, because Common Lisp's append can take more than two arguments. It's close enough to demonstrate why all but the last list is copied, though. Now look at what that means in terms of your implementation of rev, though:
(defun rev (l)
(cond
((null l) '())
(T (append (rev (cdr l)) (list (car l))))))
This means that when you're reversing a list like (1 2 3 4), it's like you're:
(append '(4 3 2) '(1)) ; as a result of (1)
(append (append '(4 3) '(2)) '(1)) ; and so on... (2)
Now, in line (2), you're copying the list (4 3). In line one, you're copying the list (4 3 2) which includes a copy of (4 3). That is, you're copying a copy. That's a pretty wasteful use of memory.
A more common approach uses an accumulator variable and a helper function. (Note that I use endp, rest, first, and list* instead of null, cdr, car, and cons, since it makes it clearer that we're working with lists, not arbitrary cons-trees. They're pretty much the same (but there are a few differences).)
(defun rev-helper (list reversed)
"A helper function for reversing a list. Returns a new list
containing the elements of LIST in reverse order, followed by the
elements in REVERSED. (So, when REVERSED is the empty list, returns
exactly a reversed copy of LIST.)"
(if (endp list)
reversed
(rev-helper (rest list)
(list* (first list)
reversed))))
CL-USER> (rev-helper '(1 2 3) '(4 5))
(3 2 1 4 5)
CL-USER> (rev-helper '(1 2 3) '())
(3 2 1)
With this helper function, it's easy to define rev:
(defun rev (list)
"Returns a new list containing the elements of LIST in reverse
order."
(rev-helper list '()))
CL-USER> (rev '(1 2 3))
(3 2 1)
That said, rather than having an external helper function, it would probably be more common to use labels to define a local helper function:
(defun rev (list)
(labels ((rev-helper (list reversed)
#| ... |#))
(rev-helper list '())))
Or, since Common Lisp isn't guaranteed to optimize tail calls, a do loop is nice and clean here too:
(defun rev (list)
(do ((list list (rest list))
(reversed '() (list* (first list) reversed)))
((endp list) reversed)))
In ANSI Common Lisp, you can reverse a list using the reverse function (nondestructive: allocates a new list), or nreverse (rearranges the building blocks or data of the existing list to produce the reversed one).
> (reverse '(1 2 3))
(3 2 1)
Don't use nreverse on quoted list literals; it is undefined behavior and may behave in surprising ways, since it is de facto self-modifying code.
You've likely run out of stack space; this is the consequence of calling a recursive function, rev, outside of tail position. The approach to converting to a tail-recursive function involves introducing an accumulator, the variable result in the following:
(defun reving (list result)
(cond ((consp list) (reving (cdr list) (cons (car list) result)))
((null list) result)
(t (cons list result))))
You rev function then becomes:
(define rev (list) (reving list '()))
Examples:
* (reving '(1 2 3) '())
(3 2 1)
* (reving '(1 2 . 3) '())
(3 2 1)
* (reving '1 '())
(1)
If you can use the standard CL library functions like append, you should use reverse (as Kaz suggested).
Otherwise, if this is an exercise (h/w or not), you can try this:
(defun rev (l)
(labels ((r (todo)
(if todo
(multiple-value-bind (res-head res-tail) (r (cdr todo))
(if res-head
(setf (cdr res-tail) (list (car todo))
res-tail (cdr res-tail))
(setq res-head (list (car todo))
res-tail res-head))
(values res-head res-tail))
(values nil nil))))
(values (r l))))
PS. Your specific error is incomprehensible, please contact your vendor.
This is the Common Lisp code:
(defun take (L)
(if (null L) nil
(cons (car L) (skip (cdr L)))))
(defun skip (L)
(if (null L) nil
(cons (car L) (take (cdr L)))))
The idea here is that, "take" will give all the odd sequence elements in the input list and "skip" will give all the even sequence elements in the input list. However, in both cases the entire list is returned.
What is the error in this code? Is this something to do with how CL handles lists, because the similar code in SML gives the desired output.
fun take(lst) =
if lst = nil then nil
else hd(lst)::skip(tl(lst))
and
skip(lst) =
if lst = nil then nil
else hd(lst)::take(tl(lst));
To expound on what Sylwester has said, your skip is wrong in both Lisp and SML. It should be
(defun take (L) ; even-indexed elements of a list L
(if (not (null L))
(cons (car L) (skip (cdr L)))))
(defun skip (L) ; odd-indexed elements of a list L
(if (not (null L))
(take (cdr L))))
and
fun take(lst) =
if lst = nil then nil
else hd(lst)::skip(tl(lst))
and
skip(lst) =
if lst = nil then nil
else take(tl(lst));
The take and skip are identical so that is no mystery. skip should just tail call instead of cons-ing. It's the consing that makes the return here.
It's worth pointing out that indexing in Common Lisp (like many other programming languages) starts with 0, so the even-indexed elements of a list are the first, the third, the fifth, and so on, since those have indices 0, 2, 4, etc. It's also worth noting that in Common Lisp, you can take the rest of the empty list and get back the empty list. (You can't do this in every Lisp, though. E.g., in Scheme it's an error to call cdr on something that's not a pair.) This means that you can implement even-elements and odd-elements rather easily. even-elementsjust returns a list of the first element, and the odd elements of the rest of the list. odd-elements returns the even-elements of the rest of the list:
(defun even-elements (list)
(if (endp list) list
(list* (first list) (odd-elements (rest list)))))
(defun odd-elements (list)
(even-elements (rest list)))
These behave in the expected fashion:
CL-USER> (even-elements '(0 1 2 3 4 5))
(0 2 4)
CL-USER> (odd-elements '(0 1 2 3 4 5))
(1 3 5)
Of course, if you note that the call to (odd-elements x) is just a call to (even-elements (rest x)), we could have implemented even-elements as follows, and had the same result:
(defun even-elements (list)
(if (endp list) list
(list* (first list) (even-elements (rest (rest list))))))
I'm new to LISP so I'm not very good at this... So my problem is, I've been given a structure (list of lists) and my job is to create a function that retrives the second item in each sub list (counting from 0). So in the end I would like to return (fruit fruit agent yard).
I can do the basic recursion calls that goes through the lists but I can't seem to figure out how to get the second item in the sub list.
Structure of the lists:
(defparameter *jack*
'((orange#8 apple fruit basment)
(pear#12 mango fruit basment)
(jones rabbit agent closet)
(jack dog agent yard)
))
Code I have so far:
(defun attempt(*data*)
(cond ((null *data*)
nil
)
((attempt (rest *data*)))
))
What I'm thinking is that I should be iterating through the list sub lists using first and rest but like I said, I can't figure it out. Help?
CL-USER> (mapcar #'caddr *jack*)
(FRUIT FRUIT AGENT AGENT)
EDIT: If you want to practise your recursive approach, try:
(defun attempt (list-of-lists)
(if (null list-of-lists) nil
(cons (third (car list-of-lists))
(attempt (cdr list-of-lists)))))
EDIT2: Tail-recursively:
(defun attempt-tail (list-of-lists)
(labels ((iter (rest ans)
(if (null rest) (nreverse ans)
(iter (cdr rest) (push (third (car rest)) ans)))))
(iter list-of-lists nil)))
EDIT3: While I'm at it, here's the loop version:
(loop for list in *jack* collect (third list))
This is most probably what you are looking for:
(mapcar #'cadr *jack*)
yes you can define for this process you want a tail-recursive procedure;
(defun nths (n l)"returns list of nths of a list of lists l"
(nths-aux n l '()))
(defun nths-aux (n l A)
(if (null l) A;or (reverse A)
(nths-aux n (cdr l) (cons (nth n (car l)) A))))
I would like to write a function that reverses the elements of a list, but it should happen in place (that is, don't create a new reversed list).
Something like:
>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)
What flags should I follow to achieve this?
Have a look at nreverse which will modify the list in place (see HyperSpec).
As per the comments, do note the comments that #Barmar made and this bit from the spec:
For nreverse, sequence might be destroyed and re-used to produce the result. The result might or might not be identical to sequence. Specifically, when sequence is a list, nreverse is permitted to setf any part, car or cdr, of any cons that is part of the list structure of sequence.
It's not difficult to implement this (ignoring fault cases). The keys are to use (setf cdr) to reuse a given cons cell and not to lose the reference to the prior cdr.
(defun nreverse2 (list)
(recurse reving ((list list) (rslt '()))
(if (not (consp list))
rslt
(let ((rest (cdr list)))
(setf (cdr list) rslt)
(reving rest list)))))
(defmacro recurse (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,#body))
(,name ,#(mapcar #'cadr args))))
[edit] As mentioned in a comment, to do this truly in-place (and w/o regard to consing):
(defun reverse-in-place (l)
(let ((result l))
(recurse reving ((l l) (r (reverse l))
(cond ((not (consp l)) result)
(else (setf (car l) (car r))
(reving (cdr l) (cdr r)))))))
> (defvar l '(1 2 3))
> (reverse-in-place l))
(3 2 1)
> l
(3 2 1)
I apologize for the bad English..
I have a task to write a function called "make-bag" that counts occurences of every value in a list
and returns a list of dotted pairs like this: '((value1 . num-occurences1) (value2 . num-occurences2) ...)
For example:
(make-bag '(d c a b b c a))
((d . 1) (c . 2) (a . 2) (b . 2))
(the list doesn't have to be sorted)
Our lecturer allows us to us functions MAPCAR and also FILTER (suppose it is implemented),
but we are not allowed to use REMOVE-DUPLICATES and COUNT-IF.
He also demands that we will use recursion.
Is there a way to count every value only once without removing duplicates?
And if there is a way, can it be done by recursion?
First of, I agree with Mr. Joswig - Stackoverflow isn't a place to ask for answers to homework. But, I will answer your question in a way that you may not be able to use it directly without some extra digging and being able to understand how hash-tables and lexical closures work. Which in it's turn will be a good exercise for your advancement.
Is there a way to count every value only once without removing duplicates? And if there is a way, can it be done by recursion?
Yes, it's straight forward with hash-tables, here are two examples:
;; no state stored
(defun make-bag (lst)
(let ((hs (make-hash-table)))
(labels ((%make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(%make-bag (cdr lst)))
hs)))
(%make-bag lst))))
Now, if you try evaluate this form twice, you will get the same answer each time:
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
(gethash 'a (make-bag '(a a a a b b b c c b a 1 2 2 1 3 3 4 5 55)))
> 5
> T
And this is a second example:
;; state is stored....
(let ((hs (make-hash-table)))
(defun make-bag (lst)
(if lst
(multiple-value-bind (val exists)
(gethash (car lst) hs)
(if exists
(setf (gethash (car lst) hs) (1+ val))
(setf (gethash (car lst) hs) 1))
(make-bag (cdr lst)))
hs)))
Now, if you try to evaluate this form twice, you will get answer doubled the second time:
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 5
> T
(gethash 'x (make-bag '(x x x y y x z z z z x)))
> 10
> T
Why did the answer doubled?
How to convert contents of a hash table to an assoc list?
Also note that recursive functions usually "eat" lists, and sometimes have an accumulator that accumulates the results of each step, which is returned at the end. Without hash-tables and ability of using remove-duplicates/count-if, logic gets a bit convoluted since you are forced to use basic functions.
Well, here's the answer, but to make it a little bit more useful as a learning exercise, I'm going to leave some blanks, you'll have to fill.
Also note that using a hash table for this task would be more advantageous because the access time to an element stored in a hash table is fixed (and usually very small), while the access time to an element stored in a list has linear complexity, so would grow with longer lists.
(defun make-bag (list)
(let (result)
(labels ((%make-bag (list)
(when list
(let ((key (assoc (car <??>) <??>)))
(if key (incf (cdr key))
(setq <??>
(cons (cons (car <??>) 1) <??>)))
(%make-bag (cdr <??>))))))
(%make-bag list))
result))
There may be variations of this function, but they would be roughly based on the same principle.