Deleting an item from a list in Common Lisp - list

I'm trying to write a function in Common Lisp that deletes an item from a list. Here's what I've written so far:
(defun aux-remove-fio (lst toremove)
(if (equal (first lst) toremove)
(pop lst)
(aux-remove-fio (rest lst) toremove))))
When I test the function, here's the result:
CG-USER(49): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(50): (pop a3)
(1 (1 . 1) (1 . 2))
CG-USER(51): a3
((2 (2 . 1) (1 . 2)))
CG-USER(52): (setf a3 '((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2))))
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(53): (aux-remove-fio a3 '(1 (1 . 1) (1 . 2)))
(1 (1 . 1) (1 . 2))
CG-USER(54): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
Can anyone explain why my function isn't working?

Yes. Your function changes the value of its local variable, lst --- nothing more.
Here is a simpler example, showing the same thing:
(setq a3 '(1 2 3)) ; (1 2 3)
(defun foo (xs) (setq xs (cdr xs))) ; Change value of xs.
;; Change value of xs to (2 3). Its initial value is the value of a3, i.e., (1 2 3)
(foo a3)
a3 ; => (1 2 3)
After foo is called, a3 still points to the original cons cell whose car is 1 and whose cdr is the same cons cell as before, with car 2, etc. All you have done i smake local variable xs point to the cdr of the cons cell it originally pointed to, which was the same cons cell that a3 points to.
If you want your function to change the value of global variable a3, then do so directly:
(defun foo () (pop a3))
Or if you just want a function that pops the first element off of the list value of a special variable, then you have such a function: pop --- just use (pop a3).
If you want a function that changes the value of a global variable that you pass it, then pass the variable (i.e., symbol) and not its value:
(defun foo (var)
(let* ((val (symbol-value var))
(head (car val)))
(set var (cdr val))
head))
(foo 'a3) ; Pop off a3's head and return it.
a3 ; Now a3 has lost its head.
This definition of foo is like a simple form of pop, except that it is a function, so evaluates its argument.

This is my simple solution. I define a function in REPL
CL-USER> (defun remove-element (mylist n)
(append
(subseq mylist 0 n)
(subseq mylist (1+ n))))
then run it (errors on your Lisp implementation may differ)
CL-USER> (remove-element '(1 2 3 4 5) 0)
(2 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 1)
(1 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 5)
; Evaluation aborted on #<SB-KERNEL:BOUNDING-INDICES-BAD-ERROR ...
CL-USER> (remove-element '(1 2 3 4 5) -1)
; Evaluation aborted on #<TYPE-ERROR ...

Related

How to transform list into sub lists?

((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
from
(1 2 3 4 5 6)
And what is the type of such operation?
What I tried:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
You're pushing the same sublist every time through the loop.
You can use :for sublist on to loop over successive tails of a list.
And use :collect to make a list of all the results, rather than pushing onto your own list
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
Alternatively use map:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
You can read it as:
for list l with values (1 2 3 4 5 6)
map over the list and its two successive cdrs
by applying #'list on the elements of the lists map is looping through in parallel
(stopping when shortest list is used up)
and collecting the results as/into a 'list
#WillNess suggested even simpler:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
thanks! So then we could generalize using only map variants:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l) is equivalent to (loop for sl on l collect sl).
However,
(loop for sl on l
for i from 0 to n
collect sl)
is better because it stops at n-th round of looping ...
First let's define a function take-n, which either returns n items or an empty list, if there are not enough items. It will not scan the whole list.
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
Then we move this function take-n over the list until it returns NIL.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
Example:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
Here's a version of Barmar's answer (which should be the accepted one) which is a bit more general and only calls length once.
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
Or the classical more C-like for-loop-ing with indexes to solve it.
But use it more on strings/vectors but less on lists, because its performance is
for lists quadratic
for vectors (strings!) linear, so preferably to be used with them!
credits and thanks to #WillNess who pointed both points out (see comments below).
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
So on vectors/strings use:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")

LISP. Create list of pairs

I have a code like below. It return list as (((1 . 2) (1 . 0)) ((1 . 2) (1 . 1)) ((1 . 2) (1 . 3)) ((1 . 2) (1 . 4)) ((1 . 2) (1 . 5)) ((1 . 2) (1 . 6)) ((1 . 2) (1 . 7)) ((1 . 2) (0 . 2)) ((1 . 2) (2 . 2)))
I wonder if I can rewrite generHod function in the way to make it return list like ((1.2 1.0) (3.4 4.2) (1.3 1.3)...)
(setf hod '())
(defun generHod (CurrX CurrY)
(dotimes (y 8)
(if (/= y CurrY)
(setf hod (append hod (list (append (list (cons CurrX CurrY))(list (cons CurrX y))))))
)
)
(dotimes (x 8)
(if (/= x CurrX)
(setf hod (append hod (list (append (list (cons CurrX CurrY))(list (cons x CurrY))))))
)
)
)
Firstly:
(setf hod '())
This is a bad way to define a global variable; try
(defparameter hod ())
But why use a global variable at all? The function can construct a new list and just return it. If the caller wants to stick it into a global variable, that's up to the caller; it's extraneous to the operation of the function.
(defun generHod ...)
The syntax generHod is not distinguished from GENERHOD or generhod in Common Lisp, under the default readtable. All those tokens produce the same symbol. It is best not to play mixed case games in Lisp identifiers; if you want multiple words, put in a dash like gen-hod. Usually generate is abbreviated all the way to gen by English speaking hackers, not gener. See the gensym funtion in Common Lisp, for instance.
In your function, there is a completely superfluous append:
(append
(list (cons CurrX CurrY))
(list (cons CurrX y))))
The pattern (append (list X0) (list X1) ... (list XN)) can be rewritten (list X0 X1 ... XN). You're making superfluous lists of things only to append them together to make one list, instead of just listing the things in the first place.
To get the values from integer to floating point, the float function can be used, and the loop macro provides an idiom for iterating and collecting items:
(defun gen-hod (curr-x curr-y)
(let ((cxy (list (float curr-x) (float curr-y)))) ;; allocate just once!
(nconc ;; destructive append: use with care
(loop for y from 1 to 8
when (/= y curr-y)
append (list cxy (list (float curr-x) (float y))))
(loop for x from 1 to 8
when (/= x curr-x)
append (list cxy (list (float x) (float curr-y)))))))

Change the copy of the list without changing the orginal one in Lisp

How can I change the elements of a list's copy without changing the elements of the original list in Common Lisp?
copy-list copies the top level structure of its argument list. If you intend to surgically modify the values inside, you will need to copy them as well.
[3]> (defvar a (list (list 1 2) (list 3 4) 5 (list 6)))
((1 2) (3 4) 5 (6))
[4]> (defvar b (copy-list a))
B
[5]> b
((1 2) (3 4) 5 (6))
[6]> (setf (third b) 55)
55
[7]> b
((1 2) (3 4) 55 (6))
[8]> a
((1 2) (3 4) 5 (6)) ;; top level value changed independently
[9]> (setf (second (second b)) 44)
44
[10]> b
((1 2) (3 44) 55 (6))
[11]> a
((1 2) (3 44) 5 (6)) ;; deeper change reflected in the original
So before you make a deeper change, do make a deeper copy, as (setf (second b) (copy-list (second a))), first:
[12]> (setf (second b) (copy-list (second a)))
(3 44)
[13]> (setf (second (second b)) 444)
444
[14]> b
((1 2) (3 444) 55 (6))
[15]> a
((1 2) (3 44) 5 (6))
Copy the list with COPY-LIST. The you can delete or add elements of the new list and the old list won't change.
You need to make new cons until the element you want to replace. Eg.
; example
(defparameter *test* '(1 2 (3 4 5 6) 7 8))
;; change 4 in the structure in *test* to 99
(list* (car *test*)
(cadr *test*)
(list* (caaddr *test*)
99 ; the actual change
(cdaddr *test*)) ; shared sublist tail
(cdddr *test*)) ; shared tail
; ==> (1 2 (3 99 4 5 6) 7 8)
Here the end of the sublist and the end of the main list shares structure since it doesn't need to be changed.
How to search a tree and replace one subtree with another:
;; replace all occurences of target in source with replacement
(defun find-replace (source target replacement)
(cond ((equal source target) replacement) ;; equal, return replacement
((not (consp source)) source) ;; not equal && not pair, return source
(t (cons (find-replace (car source) target replacement) ;; recurse
(find-replace (cdr source) target replacement)))))
(find-replace *test* 4 99) ; ==> (1 2 (3 99 4 5 6) 7 8)
(find-replace *test* '(3 4 5 6) "banan") ; ==> (1 2 "banan" 7 8)

Strange behavior invoking destructive Common LISP function receiving as argument a list created with quote

I've been getting a strange behavior when invoking a destructive definition receiving as argument a local variable whose type is a list created with a quote.
Destructive function:
(defun insert-at-pos (pos list elem)
(if (= pos 0)
(cons elem list)
(let ((aux-list (nthcdr (1- pos) list)))
(setf (rest aux-list) (cons elem (rest aux-list)))
list)))
WRONG: Local variable is a list created with the special operator quote.
(defun test ()
(let ((l '(1 2 3)))
(print l)
(insert-at-pos 2 l 4)
(print l)))
> (test)
(1 2 3)
(1 2 4 3)
(1 2 4 3)
> (test)
(1 2 4 3)
(1 2 4 4 3)
(1 2 4 4 3)
> (test)
(1 2 4 4 3)
(1 2 4 4 4 3)
(1 2 4 4 4 3)
CORRECT: Local variable is a list created with function list.
(defun test2 ()
(let ((l (list 1 2 3)))
(print l)
(insert-at-pos 2 l 4)
(print l)))
or
(defun test2 ()
(let ((l '(1 2 3)))
(print l)
(setf l (cons (first l) (cons (second l) (cons 4 (nthcdr 2 l)))))
(print l)))
> (test2)
(1 2 3)
(1 2 4 3)
(1 2 4 3)
> (test2)
(1 2 3)
(1 2 4 3)
(1 2 4 3)
> (test2)
(1 2 3)
(1 2 4 3)
(1 2 4 3)
Does someone know the reason of this strange behaviour?
If you quote data in a function, then it is literal data. The effects of destructively modifying such literal data are undefined in the Common Lisp standard. In your example all function invocations share the same literal data and the implementation does not warn you that you are changing it. That's what most implementations do. But it would also possible to imagine an implementation which puts all code (and its literal data) into a read-only part of the memory.
You can get funky effects with this.
If you want to destructively modify a list without running into potential problems, then you need to create a fresh copy at runtime. For example by calling LIST or COPY-LIST. LIST will return a fresh consed list.
There are similar pitfalls. For example imagine a file with these definitions:
(defvar *foo* '(1 2 3 4 5 6 ... 10000))
(defvar *foo* '(0 1 2 3 4 5 6 ... 10000))
If you compile such a file with the file compiler, the compiler is allowed to create a compiled file, where the two variables share literal data - saving space. If you would change an element in either list, both might be changed.

Building a 2D List

Looking for a function that would do something akin to the following:
(foo 3 2) => '( ( (1 1) (1 2) (1 3) )
( (2 1) (2 2) (2 3) ) )
Would there be any built-in function in DrRacket that accomplishes that?
The main tool that you want to use to get such things in Racket is the various for loops. Assuming that you want to create a list-based matrix structure, then this is one way to get it:
#lang racket
(define (foo x y)
(for/list ([i y])
(for/list ([j x])
(list (add1 i) (add1 j)))))
And since people raised the more general question of how to make foo create a matrix of any dimension, here's a generalized version that works with any number of arguments, and still returns the same result when called as (foo 3 2):
#lang racket
(define (foo . xs)
(let loop ([xs (reverse xs)] [r '()])
(if (null? xs)
(reverse r)
(for/list ([i (car xs)])
(loop (cdr xs) (cons (add1 i) r))))))
(Note BTW that in both cases I went with a simple 0-based iteration, and used add1 to get the numbers you want. An alternative way would be to replace
(for/list ([i x]) ... (add1 i) ...)
with
(for/list ([i (in-range 1 (add1 x)]) ... i ...)
)
Code:
(define (foo-makey const max data)
(let* ((i (length data))
(newy (- max i))
(newpair (cons const newy)))
(if (= max i)
data
(foo-makey const max
(cons newpair data)))))
(define (foo-makex xmax ymax data)
(let* ((i (length data))
(newx (- xmax i)))
(if (= xmax i)
data
(foo-makex xmax ymax
(cons (foo-makey newx ymax '()) data)))))
(define (foo x y)
(foo-makex y x '()))
Output:
> (foo 3 2)
'(((1 . 1) (1 . 2) (1 . 3)) ((2 . 1) (2 . 2) (2 . 3)))
I can't answer your question as-is because I don't understand how the nested lists should work for >2 arguments. AFAIK there is no built-in function to do what you want.
To start you off, here is some code that generates output without nested lists. As an exercise try adjusting the code to do the nested listing. And see if there's a way you can make the code more efficient.
;;can take in any number of arguments
(define (permutations . nums)
(foldl
(lambda (current-num acc)
(append-map
(lambda (list-in-acc)
(for/list ((i (build-list current-num (curry + 1))))
(append list-in-acc (list i))))
acc))
(list (list))
(reverse nums)))
Example 1:
> (permutations 3 2)
'((1 1) (1 2) (1 3) (2 1) (2 2) (2 3))
Example 2:
> (permutations 10)
'((1) (2) (3) (4) (5) (6) (7) (8) (9) (10))
Example 3:
> (permutations 2 3 4)
'((1 1 1)
(1 1 2)
(1 2 1)
(1 2 2)
(1 3 1)
(1 3 2)
(2 1 1)
(2 1 2)
(2 2 1)
(2 2 2)
(2 3 1)
(2 3 2)
(3 1 1)
(3 1 2)
(3 2 1)
(3 2 2)
(3 3 1)
(3 3 2)
(4 1 1)
(4 1 2)
(4 2 1)
(4 2 2)
(4 3 1)
(4 3 2))
(define (build-2d row col)
(build-list row (lambda(x) (build-list col (lambda(y) (list (+ x 1) (+ y 1))))))