Basic LISP recursive replacement of substring - replace

I'm trying to replace any occurrences of a given string in a list with "X", using basic LISP commands (e.g. no mapcar) in a recursive function.
(defun removetext (symbol list replaced)
(if (not list) ; if initial list has been exhausted, return replaced list
replaced
(progn
(if (eql (car list) symbol) ; otherwise, if first element of list = symbol, replace with "X"
(removetext symbol (cdr list) (cons "X" replaced))
(removetext symbol (cdr list) (cons (car list) replaced)) ; otherwise keep it
)
(format t "~D" replaced)
)
)
)
This does not work if I call it with (removetext "E" '(A B C D E F F E) "").
This returns NIL and the printout looks like (F F E D C B A . )(F E D C B A . )(E D C B A . )(D C B A . )(C B A . )(B A . )(A . ).
I want it to return (A B C D X F F X).

(defun removetext (symbol list replaced)
(if (null list)
(reverse replaced)
(if (eql (car list) symbol)
(removetext symbol (cdr list) (cons 'x replaced))
(removetext symbol (cdr list) (cons (car list) replaced)))))
Example:
CL-USER > (removetext 'E '(A B C D E F F E) ())
(A B C D X F F X)

None of the other answers so far have addressed an important problem in your code. Given this slightly different but structurally similar version of your function:
(defun replace-thing (list thing by &key (test #'eql))
(labels ((replace-it (tail replaced)
(if (null tail)
(reverse replaced)
(progn
(if (funcall test (first tail) thing)
(replace-it (rest tail) (cons by replaced))
(replace-it (rest tail) (cons (first tail) replaced)))
(format t "~&got ~S~%" replaced)))))
(replace-it list '())))
This will fail in the same way as one of the ways yours does:
> (replace-thing '(a b c) 'a 'c)
(b c)
(c)
nil
nil
And the reason it's failing is because what progn does. You've written
(progn
... compute the thing you care about ...
(format ...))
And the value(s) of progn are the value(s) of the last form in its body, so in this case the value of (format ...) which is nil.
There are two solutions to this: one that works for you and one that is more general.
The solution that works for you is to realise that replaced is never altered (your function does no mutation, which is good), so you can safely print it first:
(progn
(format t "~& ~S~%" replaced)
(if (funcall test (first tail) thing)
(replace-it (rest tail) (cons by replaced))
(replace-it (rest tail) (cons (first tail) replaced))))
This change will make my function work.
A more general solution is to realise that what you want is some form, say first-thing which, when used as
(first-thing
thing1
...
thingn)
Will:
do the things in its body in order;
then return the value(s) of the first of them.
Well, you can write such a form pretty easily as a macro. Here's a slightly restricted version:
(defmacro first-thing (thing1 &body more-things)
(let ((sn (make-symbol "STASH")))
`(let ((,sn ,thing1))
,#more-things
,sn)))
Then
> (first-thing 1 (print "hi") (print "there"))
"hi"
"there"
1
But in fact you don't need to do that: CL offers both this restricted one and a more general one:
the restricted one is prog1 – (prog1 thing1 ... thingn) evaluates the things in order and then returns the first value of the first thing;
the general one is multiple-value-prog1 – (multiple-value-prog1 thing1 ... thingn) evaluates the things in order and then returns all the values of the first one.
multiple-value-prog1 is almost certainly more expensive than prog1 since it needs to stash multiple values somewhere and hence almost certainly conses. In your case you only need prog1 though, so a version of (my version of) your function is:
(defun replace-thing (list thing by &key (test #'eql))
(labels ((replace-it (tail replaced)
(if (null tail)
(reverse replaced)
(prog1
(if (funcall test (first tail) thing)
(replace-it (rest tail) (cons by replaced))
(replace-it (rest tail) (cons (first tail) replaced)))
(format t "~& ~S~%" replaced)))))
(replace-it list '())))
And
> (replace-thing '(a b c) 'a 'z)
(b z)
(z)
nil
(z b c)

If you want to replace occurrences of a string you'll need to pass a list of strings. You passed a list of symbols, not strings. Now you can still replace those symbols with a particular string, but they are not string themselves. The list:
'(a b c d e f e)
is a list of symbols, not string:
(defun remove-text (str lst)
(if (atom lst)
lst
(if (string-equal (symbol-name (car lst)) str)
(cons "X" (remove-text str (cdr lst)))
(cons (car lst) (remove-text str (cdr lst))))))
We can pass a string as an argument to check, and then a list of symbol. Our base case will test to see if the list is an atom, at which point we will simply return the list. If not, we will use string-equal to see if the symbol name of the car of the list(which will return the string value of the symbol) is equal to our string. Then we can then cons "X" unto the beginning of the list if that is the case, and then recursively call the function again. If not, we can simply cons the car of the list to the beginning of the list, and recursively call the function again. This function is not tail-recursive, but it recursive, and it does avoid creating a new list structure to store thee result, without destructively altering the structure of the original list. We can test it below:
CL-USER> (remove-text "E" '(a b c d e f f e))
(A B C D "X" F F "X")

Related

Lisp - Get rid of dotted list

I am building a function is Lisp ta reverses the first and last element of a list. I get that a list has a car and a cdr hence why there is a dot in my output. Is there a way to remove the dot?
(defun my-butlast (list)
(loop for l on list
while (cdr l)
collect (car l)))
(defun f-l-swap(list)
(append (last list)(cdr (my-butlast list))(car list))
)
(write(f-l-swap '(A B C D E)))
OUTPUT:
(E B C D . A)
append expects arguments to be lists. In your case (car list) is an atom. You have to change it to list if you want to stick with append. Ie:
(defun f-l-swap (list)
(append (last list)
(cdr (my-butlast list))
(list (car list))))
A list is a chain of cons pairs. eg. (1 2 3) is the visualization of (1 . (2 . (3 . ()))). In the event the last cdr is not () you have what we call a dotted list since then there is no simplified visualization of the last part. It has to be printed with a dot.
You have (E . (B . (C . (D . A)))) and want to have (E . (B . (C . (D . (A . ()))))). Do you see the difference? (car list) is not a list but one elment and that is why you get a dotted list.
Here are more sensible implementations of append and butlast:
(defun my-append (a b)
(if (null a)
b
(cons (car a) (my-append (cdr a) b))))
That only supports 2 arguments, but the idea for more is that it continues until you have consed all the previous lists and only have one left, which verbatim becomes the tail. Here is how that might look:
(defun my-append2 (x &rest xs)
(labels ((helper (x xs)
(cond ((null xs) x)
((null x) (helper (car xs) (cdr xs)))
(t (cons (car x) (helper (cdr x) xs))))))
(helper x xs)))
Here is butlast
(defun my-butlast (xs)
(if (null (cdr xs))
'()
(cons (car xs) (my-butlast (cdr xs)))))
Now, one should really do it with higher order functions or loop, but then you get the facts hidden how lists work. The code above shows you have they work.

How to transform a list into a set in LISP?

I have been trying to transform a linear list into a set but with no avail. Everytime I run this, I get some weird compilation errors like "badly formed lambda" which points to the way I use append. Here is my code:
(defun mem(e l)
(cond
((null l) nil)
((equal e (car l)) t)
((listp (car l)) (mem e (car l)))
(t(mem e (cdr l)))
)
)
(defun st(l k)
(cond
((null l) nil)
(( mem '(car l) 'k) (st (cdr l) k))
((listp (car l)) (st (car l) k))
( t (st (cdr l) (append((car l) k)) ))
(t(mem e (cdr l)))
)
)
EDIT: frankly I just want to remove the duplicates from list l
Prefer Standard Library Functions
EDIT: frankly I just want to remove the duplicates from list l
Common Lisp has a remove-duplicates function. The documentation inclues examples:
Examples:
(remove-duplicates "aBcDAbCd" :test #'char-equal :from-end t) => "aBcD"
(remove-duplicates '(a b c b d d e)) => (A C B D E)
(remove-duplicates '(a b c b d d e) :from-end t) => (A B C D E)
(remove-duplicates '((foo #\a) (bar #\%) (baz #\A))
:test #'char-equal :key #'cadr) => ((BAR #\%) (BAZ #\A))
(remove-duplicates '((foo #\a) (bar #\%) (baz #\A))
:test #'char-equal :key #'cadr :from-end t) => ((FOO #\a) (BAR #\%))
Are you trying to flatten the list too?
From your code for mem, where you do:
((listp (car l)) (mem e (car l)))
it looks like you want your member function to also recurse into sublists. That's a bit questionable, even when working with sets, since sets can traditionally include other sets. E.g., {{3},{4},5} is a set containing 5, the set {3}, and the set {4}. It's not the same as the set {3,4,5}. Your st function also looks like it's trying to recurse into lists, which makes it seem like you want to flatten you lists, too. Again, that's a bit questionable, but if you want to do that, then your conversion to a set would be easier as a "flatten, then remove duplicates" process:
(defun flatten (list)
"Returns a fresh list containing the leaf elements of LIST."
(if (listp list)
(mapcan 'flatten list)
(list list)))
;; CL-USER> (flatten '(1 2 (3 4) 5 ((6))))
;; (1 2 3 4 5 6)
(defun to-set (list)
"Returns a set based on the elements of LIST. The result
is a flat list containing the leaf elements of LIST, but
with any duplicate elements removed."
(delete-duplicates (flatten list)))
;; CL-USER> (to-set '(1 3 (3 4) ((4) 5)))
;; (1 3 4 5)
Notes
I get some weird compilation errors like "badly formed lambda" which points to the way I use append.
Yes, you're trying to call append like: (append((car l) k)). That's actually not a problem for append. Remember, the syntax for a function call in Lisp is (function argument…). That means that you've got:
(append ((car l) k))
<function> <argument1>
But your argument1 is also a function call:
((car l) k )
<function> <argument1>
In Common Lisp, you can't use (car l) as a function. The only thing that can appear for a function is a symbol (e.g., car, append) or a lambda expression (e.g., (lambda (x) (+ x 1)).
You want to call (append (car l) k) instead.
First, CL does not have a set data type.
Lists, however, can be used as sets, you do not need to write any special code for that.
Second, I don't understand what your st function is supposed to do, but I bet that in the second cond clause you should not quote (car l) and k. You should use meaningful names for your functions and avoid abbreviations. As per your explanation in the comment, you should use pushnew instead.
Third, your mem function is quite weird, I am pretty sure you do not mean what you wrote: e is searched along a path in the tree l, not in the list l. As per your explanation in the comment, you should check both car and cdr:
(defun tree-member (tree element &key (test #'eql))
(if (consp tree)
(or (tree-member (car tree) element :test test)
(tree-member (cdr tree) element :test test))
(funcall test element tree)))

Every other letter in a list? LISP

I am relatively new to LISP and am trying some new things for a Lisp program I am trying to create for a presentation.
I need to be able to print every other character in a list, for example, (A B C D E F) would return (A C E) .. but I am getting easily confused...
I am normally program Java, so this comes kind of different to me.
I am trying to program this using purely recursion.. So something along the lines of....
(defun every-other (lst)
(cond ((null lst) 0)
(( **** now this is where I get confused as to what I should do..
I've tried adding a counter to only remove even numbered elements, but I think I implemented the counter wrong, I also tried remove(cadr lst) lst, but that would only return zeros...
any help would be greatly appreciated..
Thanks!
Since you say you want it to be done recursively, just think it through case by case.
The list is null -> return the empty list [the empty list is '()].
Otherwise the list is not null -> In this case you want to build a new list containing
the first element, skip the second element, then grab
every-other element of the remaining list.
Turning this case analysis into code looks something like this:
(defun every-other (lst)
(cond
;; If the list is null return the empty list.
((null lst) '())
;; If the list is not null, construct [cons] a new list with the first element of lst
;; and every-other element of the list after the first two elements [rest returns the
;; list without the first element, so we can just use it twice].
(t (cons (first lst) (every-other (rest (rest lst)))))))
Now going through the evaluation of this code should look something like this:
(every-other '(a b c d e f))
=> (cons 'a (every-other '(c d e f)))
=> (cons 'a (cons 'c (every-other '(e f))))
=> (cons 'a (cons 'c (cons 'e (every-other '())))
=> (cons 'a (cons 'c (cons 'e '())))
=> (cons 'a (cons 'c '(e)))
=> (cons 'a '(c e))
=> '(a c e)
For fun, a loop-based solution:
(defun every-other (lst)
(loop
for i in lst
for keep = t then (not keep)
if keep collect i))
Just use a loop.
(loop :for c :in '(a b c d e f) :by #'cddr
:collect c)
:By in a for-in clause sets the stepping function (default is #'cdr). In order to get every other element, step two steps each time. Cddr is a shortcut for applying cdr two times.
(defun aaa (x)
(aa (length x) x))
(defun aa (n x)
(cond ((null x) nil)
((evenp (- n (length x))) (cons (car x) (aa n (cdr x))))
(t (aa n (cdr x)))))
This is a stupid case lol~
shorter recursive solution:
(defun every-other (l)
(unless (null l)
(cons (first l) (every-other (cddr l)))))

Turning list of atoms into a single list using recursion

I'm looking for an answer that turns a list of atoms into a single list recursively.
An example would be, (slist '(a (b c) (d e (f) g) h)) into (slist (a b c d e f g h))
Any answer will be helpful.
What you're trying to do is called flattening a list. Here are a bunch of options:
; required predicate
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
; naïve version using append
(define (flatten1 lst)
(cond ((null? lst)
'())
((not (pair? lst))
(list lst))
(else
(append (flatten1 (car lst))
(flatten1 (cdr lst))))))
; naïve version using append, map, apply
(define (flatten2 lst)
(if (atom? lst)
(list lst)
(apply append (map flatten2 lst))))
; efficient version using fold-left
(define (flatten3 lst)
(define (loop lst acc)
(if (atom? lst)
(cons lst acc)
(foldl loop acc lst)))
(reverse (loop lst '())))
; very efficient version with no higher-order procedures
(define (flatten4 lst)
(let loop ((lst lst)
(acc '()))
(cond ((null? lst)
acc)
((not (pair? lst))
(cons lst acc))
(else
(loop (car lst) (loop (cdr lst) acc))))))
Any of the above will work as expected. For instance, using flatten4:
(flatten4 '(a (b c) (d e (f) g) h))
=> '(a b c d e f g h)
Depending on the interpreter you're using, it's quite possible that it already includes an implementation. For example, in Racket:
(flatten '(a (b c) (d e (f) g) h))
=> '(a b c d e f g h)
In Lisp, as opposed to Scheme, you have to accept the fact that the atom nil represents an empty list in your list structure. So, strictly speaking, when you flatten a list, you do not obtain all of the atoms from the tree structure; only those ones that do not represent empty lists and list terminators.
You also have to make a design decision: does your code handle improper lists and circular list? That is to say, what should these cases do:
(flatten '(a . b)) ;; (a b), accurate diagnostic or failure?
(flatten '#1=(a . #1#)) ;; (a), accurate diagnostic or failure?
Do you handle the situation and collect the actual non-list atoms that are present in the tree structure, regardless of cycles or improper termination? Or do you detect the situation accurately and report a meaningful diagnostic? Or just ignore the possibility and let the code blow up in lower level functions, or perform runaway recursion?
If you don't care about dealing with improper lists and circular structure, flattening a list is recursively defined like this.
A non-list is flattened by returning a list containing that atom.
A list is flattened by flattening all of its elements and catenating them.
In Lisp it's usually easier and clearer to write the code than the English spec or pseudo-code:
(defun flatten (obj)
"Simple flatten: no handling of improper lists or cycles"
(if (listp obj)
(mapcan #'flatten obj)
(list obj)))
Note that although mapcan is destructive, that doesn't present a problem here, because it only ever catenates list structure that is constructed within our function call and not any incoming list structure. Stated in other words, our output does not share structure with the input.
You've already checked a correct answer, but here is a trivial implementation which clearly indicates the recursion:
(define (slist list)
(if (null? list)
'()
(let ((next (car list))
(rest (cdr list)))
(if (list? next)
(append (slist next) (slist rest))
(cons next (slist rest))))))

In list, how can I make modifications to a list through a function which takes the list as a parameter?

I was writing a program in Lisp to put the common elements from two lists into a new one. Here is my code.
(defun test (a b)
(let ((alist nil) (blist nil))
(progn
(join a b alist blist)
(print blist))))
(defun join (a b alist blist)
(cond
((and (null a) (null b))
(setf blist (cons alist blist)))
((equal (car a) (car b))
(setf alist (cons (list (car a) (car b)) alist)))
(t (join (cdr a) (cdr b) alist blist))))
But the output of the function is alwaysnil. Then I looked up something on Internet and found out that when I try to use setf, it no longer points to the original list, instead it points to a new one. So if I cannot use setf, what else can I use to implement this?
(defun test (a b)
(let ((alist nil) (blist nil)) ; two variables initialized to NIL
(progn ; this PROGN is not needed
(join a b alist blist) ; you call a function, but ignore the
; return value? Why?
(print blist)))) ; since blist was never modified, this
; can only be the initial value, NIL
(defun join (a b alist blist) ; four new local variables
(cond
((and (null a) (null b))
(setf blist (cons alist blist))) ; why do you set the variable BLIST?
; you never use it later
((equal (car a) (car b))
(setf alist (cons (list (car a) (car b)) alist)))
; why do you set the variable ALIST?
; you never use it later
(t (join (cdr a) (cdr b) alist blist))))
; the only recursive call of JOIN
You can only change variables, which are lexically reachable.
Don't use "output" arguments in Lisp. Better return the result from the function.
Also, there is a function 'intersection' in CL which does what you want, so please use it unless it is an exercise (then you can look up its implementation).