I want to change the nth element of a list and return a new list.
I've thought of three rather inelegant solutions:
(defun set-nth1 (list n value)
(let ((list2 (copy-seq list)))
(setf (elt list2 n) value)
list2))
(defun set-nth2 (list n value)
(concatenate 'list (subseq list 0 n) (list value) (subseq list (1+ n))))
(defun set-nth3 (list n value)
(substitute value nil list
:test #'(lambda (a b) (declare (ignore a b)) t)
:start n
:count 1))
What is the best way of doing this?
How about
(defun set-nth4 (list n val)
(loop for i from 0 for j in list collect (if (= i n) val j)))
Perhaps we should note the similarity to substitute and follow its convention:
(defun substitute-nth (val n list)
(loop for i from 0 for j in list collect (if (= i n) val j)))
BTW, regarding set-nth3, there is a function, constantly, exactly for situation like this:
(defun set-nth3 (list n value)
(substitute value nil list :test (constantly t) :start n :count 1))
Edit:
Another possibility:
(defun set-nth5 (list n value)
(fill (copy-seq list) value :start n :end (1+ n)))
It depends on what you mean for "elegance", but what about...
(defun set-nth (list n val)
(if (> n 0)
(cons (car list)
(set-nth (cdr list) (1- n) val))
(cons val (cdr list))))
If you have problems with easily understanding recursive definitions then a slight variation of nth-2 (as suggested by Terje Norderhaug) should be more "self-evident" for you:
(defun set-nth-2bis (list n val)
(nconc (subseq list 0 n)
(cons val (nthcdr (1+ n) list))))
The only efficiency drawback I can see of this version is that traversal up to nth element is done three times instead of one in the recursive version (that's however not tail-recursive).
How about this:
(defun set-nth (list n value)
(loop
for cell on list
for i from 0
when (< i n) collect (car cell)
else collect value
and nconc (rest cell)
and do (loop-finish)
))
On the minus side, it looks more like Algol than Lisp. But on the plus side:
it traverses the leading portion of the input list only once
it does not traverse the trailing portion of the input list at all
the output list is constructed without having to traverse it again
the result shares the same trailing cons cells as the original list (if this is not desired, change the nconc to append)
Related
I'm trying to write a function which return an element appears n times in a list.
For example, for a list like : (setq lst '(a b b b c)), the function returns :
count-list (lst 3) --> b
But when there is two element (or more) which appears in n same time, the function only returns the first element :
count-list (lst 1) --> a
Instead of
count-list (lst 1) --> a b
Here is the function :
(defun count-list (lst nb)
(loop for x in lst do
(if (eq (count x lst) nb)
(return x)
)
)
)
What did I miss ?
return tells the count-list function to exit immediately as soon as it finds a hit, so it won't look for other elements matching the count.
One possible solution is this:
(defun count-list (lst n)
(remove-duplicates
(mapcan #'(lambda (x)
(when (eql (count x lst) n)
(list x) ))
lst )))
However, this is very inefficient since for each item the list has to be traversed twice, one for the function itself and one for count, so this would take a time proportional to the square of the length of the list.
A more efficient way would be to accumulate the values (e.g. in an assoc list) and select at the end those items matching the input count number.
(defun count-list (lst n)
(let* (count-list pair)
(dolist (x lst)
(if (setq pair (assoc x count-list))
(incf (cdr pair))
(push (cons x 1) count-list) ))
(mapcan #'(lambda (pair)
(when (eql n (cdr pair))
(list (car pair)) ))
count-list )))
I never used LISP. I assume your problem is that your function returns at the first match. Either create an array in your function for storing all the elements appearing n times and return to that array, or, for example, in Python I would use print(x) so the function does not return at the first match, like in your case.
Define the function 'mapping' that takes 2 arguments: a SIMPLE list L, and an integer value val. Every element of the list L is a list of two atoms – key and object. The function returns a list of objects whose key is less than val.
Example:
(mapping '((12 k) (7 n) (23 r) (9 p)) 13) --> (k n p)
My Code So Far:
(defun mapping (list val)
(if (consp list) ;;if list is not empty
(if (> val (caar list)) ;; check the first value in the first nested list
(cons (car(cdr list)));;if value is greater add that value to the return list
(mapping (cdr list) val)))) ;; recurse thru the list
My code has syntax erros as well as the cons statement is not returning the list of all the values of how i expect it.
It's really easy to write what you want using high-order functions, you don't need all this nested IFs.
(defun mapping (list val)
(mapcan
(lambda (el)
(if (> val (car el))
(cdr el)
nil))
list))
CL-USER> (mapping '((12 k) (7 n) (23 r) (9 p)) 13)
(K N P)
If you have to wtite recursice one:
(defun recursive-mapping (list val)
(cond
((null list) nil)
((> val (caar list)) (cons (cadar list)
(recursive-mapping (cdr list) val)))
(t (recursive-mapping (cdr list) val))))
CL-USER> (recursive-mapping '((12 k) (7 n) (23 r) (9 p)) 20)
(K N P)
I'm preparing myself for my upcoming exam in LISP and I've come across a problem I can't solve, so I was hoping someone more experienced might help me out.Im trying to make a recursive lisp program that returns the position of an element n from a list but i cant use nth.I need to verify if n is in the list between 0 and length of the list -1 if the element is not in the list a error message should appear.
Something like this:(my-list '(1 2 3) 4) =>"error the list has only 3 elements"
Can someone help me with this problem Im still a novice when it comes to LISP
My code so far:
(defun no-nth (n list)
(declare (type (integer 0) n) (type list))
(if (or (zerop n) (null list))
(cons (car list) (no-nth (1- n) (cdr list)))))
Use labels to make a helper. You have the list and an index as argument. When the list is empty you return whatever you do when it's not found, perhaps nil. If not you check the first element with your search term and return index if it's a match. If not you recur with rest of the list and the increment of the index.
Both your problem description and code are confused.
Let's settle for the name no-nth and the parameter order n, then list.
So you have 3 different cases:
n < 0 or list is empty => element could not be found => return nil
n = 0 => result is first element of the list (assuming that the first position is index 0)
n > 0 => recurse by decrementing n and shortening the list by 1.
The code would then be:
(defun no-nth (n list)
(cond
((or (< n 0) (null list)) nil) ; (1) index not in list
((zerop n) (car list)) ; (2) index = 0 => return first element of list
(t (no-nth (1- n) (cdr list))))); (3) index > 0 => recurse down
Do you think of something like this?
(defun no-nth (n list)
(labels ((nth-intern (n list)
(if (zerop n) (car list)
(nth-intern (1- n) (cdr list)))))
(if (< (list-length list) n)
(error "LIST has no Nth element.")
(nth-intern n list))))
(defun help-func (n list)
(cond
((= n 1) (car list))
(T (help-func (1- n) (cdr list)))))
(defun no-nth (n list)
(cond
((or (< n 0) (>= n (length list))) 'invalid-index)
(T (help-func n list))))
(print (no-nth 2 '(1 2 3)))
(print (no-nth 21 '(1 2 3)))
If you want to see the result: http://ideone.com/zW0gvD
First you check if the index is valid, if it's not, you return invalid-index.
If it's valid, you call help-func, a recursive function.
Recursively, you decrease n until you get to n=1 (or n=0, if you want a zero base index element).
SICP contains an partially complete example of the n-queens solutions, by walking a tree of every possible queen placement in the last row, generating more possible positions in the next row to combine the results so far, filtering the possibilities to keep only ones where the newest queen is safe, and repeating recursively.
This strategy blows up after about n=11 with a maximum recursion error.
I've implemented an alternate strategy that does a smarter tree-walk from the first column, generating possible positions from a list of unused rows, consing each position-list onto an updated list of yet-unused rows. Filtering those pairs considered safe, and recursively mapping over these pairs for the next column. This doesn't blow up (so far) but n=12 takes a minute and n=13 takes about 10 minutes to solve.
(define (queens board-size)
(let loop ((k 1) (pp-pair (cons '() (enumerate-interval 1 board-size))))
(let ((position (car pp-pair))
(potential-rows (cdr pp-pair)))
(if (> k board-size)
(list position)
(flatmap (lambda (pp-pair) (loop (++ k) pp-pair))
(filter (lambda (pp-pair) (safe? k (car pp-pair))) ;keep only safe
(map (lambda (new-row)
(cons (adjoin-position new-row k position)
(remove-row new-row potential-rows))) ;make pp-pair
potential-rows)))))))
;auxiliary functions not listed
Not really looking for code, but a simple explanation of a strategy or two that's less naive and that clicks well with a functional approach.
I can offer you a simplification of your code, so it may run a little bit faster. We start by renaming some variables for improved readability (YMMV),
(define (queens board-size)
(let loop ((k 1)
(pd (cons '() (enumerate-interval 1 board-size))))
(let ((position (car pd))
(domain (cdr pd)))
(if (> k board-size)
(list position)
(flatmap (lambda (pd) (loop (1+ k) pd))
(filter (lambda (pd) (safe? k (car pd))) ;keep only safe NewPositions
(map (lambda (row)
(cons (adjoin-position row k position) ;NewPosition
(remove-row row domain))) ;make new PD for each Row in D
domain))))))) ; D
Now, filter f (map g d) == flatmap (\x->let {y=g x} in [y | f y]) d (using a bit of Haskell syntax there), i.e. we can fuse the map and the filter into one flatmap:
(flatmap (lambda (pd) (loop (1+ k) pd))
(flatmap (lambda (row) ;keep only safe NewPositions
(let ( (p (adjoin-position row k position))
(d (remove-row row domain)))
(if (safe? k p)
(list (cons p d))
'())))
domain))
then, flatmap h (flatmap g d) == flatmap (h <=< g) d (where <=< is right-to-left Kleisli composition operator, but who cares), so we can fuse the two flatmaps into just one, with
(flatmap
(lambda (row) ;keep only safe NewPositions
(let ((p (adjoin-position row k position)))
(if (safe? k p)
(loop (1+ k) (cons p (remove-row row domain)))
'())))
domain)
so the simplified code is
(define (queens board-size)
(let loop ((k 1)
(position '())
(domain (enumerate-interval 1 board-size)))
(if (> k board-size)
(list position)
(flatmap
(lambda (row) ;use only the safe picks
(if (safe_row? row k position) ;better to test before consing
(loop (1+ k) (adjoin-position row k position)
(remove-row row domain))
'()))
domain))))
Here's what I came up with a second time around. Not sure it's terribly much faster though. Quite a bit prettier though.
(define (n-queens n)
(let loop ((k 1) (r 1) (dangers (starting-dangers n)) (res '()) (solutions '()))
(cond ((> k n) (cons res solutions))
((> r n) solutions)
((safe? r k dangers)
(let ((this (loop (+ k 1) 1 (update-dangers r k dangers)
(cons (cons r k) res) solutions)))
(loop k (+ r 1) dangers res this)))
(else (loop k (+ r 1) dangers res solutions)))))
Big thing is using a let statement to serialize recursion, limiting depth to n. Solutions come out backwards (could probably fix by going n->1 instead of 1->n on r and k) but a backwards set is the same set as the frowards set.
(define (starting-dangers n)
(list (list)
(list (- n))
(list (+ (* 2 n) 1))))
;;instead of terminating in null list, terminate in term that cant threaten
small improvement, a danger can come from a row, a down diagonal, or and up diagonal, keep track of each as the board evolves.
(define (safe? r k dangers)
(and (let loop ((rdangers (rdang dangers)))
(cond ((null? rdangers) #t)
((= r (car rdangers))
#f)
(else (loop (cdr rdangers)))))
(let ((ddiag (- k r)))
(let loop ((ddangers (ddang dangers)))
(if (<= (car ddangers) ddiag)
(if (= (car ddangers) ddiag)
#f
#t)
(loop (cdr ddangers)))))
(let ((udiag (+ k r)))
(let loop ((udangers (udang dangers)))
(if (>= (car udangers) udiag)
(if (= (car udangers) udiag)
#f
#t)
(loop (cdr udangers)))))))
medium improvement in the change of format, only needing to do one comparison to check vs prior two. Don't think keeiping diagonals sorted cost me anything, but I don't think it saves time either.
(define (update-dangers r k dangers)
(list
(cons r (rdang dangers))
(insert (- k r) (ddang dangers) >)
(insert (+ k r) (udang dangers) <)))
(define (insert x sL pred)
(let loop ((L sL))
(cond ((null? L) (list x))
((pred x (car L))
(cons x L))
(else (cons (car L)
(loop (cdr L)))))))
(define (rdang dangers)
(car dangers))
(define (ddang dangers)
(cadr dangers))
(define (udang dangers)
(caddr dangers))
I've a question, how to return a list without the nth element of a given list? E.g., given list: (1 2 3 2 4 6), and given n = 4, in this case the return list should be (1 2 3 4 6).
A simple recursive solution:
(defun remove-nth (n list)
(declare
(type (integer 0) n)
(type list list))
(if (or (zerop n) (null list))
(cdr list)
(cons (car list) (remove-nth (1- n) (cdr list)))))
This will share the common tail, except in the case where the list has n or more elements, in which case it returns a new list with the same elements as the provided one.
Using remove-if:
(defun foo (n list)
(remove-if (constantly t) list :start (1- n) :count 1))
butlast/nthcdr solution (corrected):
(defun foo (n list)
(append (butlast list (1+ (- (length list) n))) (nthcdr n list)))
Or, maybe more readable:
(defun foo (n list)
(append (subseq list 0 (1- n)) (nthcdr n list)))
Using loop:
(defun foo (n list)
(loop for elt in list
for i from 1
unless (= i n) collect elt))
Here's an interesting approach. It replaces the nth element of a list with a new symbol and then removes that symbol from the list. I haven't considered how (in)efficient it is though!
(defun remove-nth (n list)
(remove (setf (nth n list) (gensym)) list))
(loop :for i :in '(1 2 3 2 4 6) ; the list
:for idx :from 0
:unless (= 3 idx) :collect i) ; except idx=3
;; => (1 2 3 4 6)
loop macro can be very useful and effective in terms of generated code by lisp compiler and macro expander.
Test run and apply macroexpand above code snippet.
A slightly more general function:
(defun remove-by-position (pred lst)
(labels ((walk-list (pred lst idx)
(if (null lst)
lst
(if (funcall pred idx)
(walk-list pred (cdr lst) (1+ idx))
(cons (car lst) (walk-list pred (cdr lst) (1+ idx)))))))
(walk-list pred lst 1)))
Which we use to implement desired remove-nth:
(defun remove-nth (n list)
(remove-by-position (lambda (i) (= i n)) list))
And the invocation:
(remove-nth 4 '(1 2 3 2 4 6))
Edit: Applied remarks from Samuel's comment.
A destructive version, the original list will be modified (except when n < 1),
(defun remove-nth (n lst)
(if (< n 1) (cdr lst)
(let* ((p (nthcdr (1- n) lst))
(right (cddr p)))
(when (consp p)
(setcdr p nil))
(nconc lst right))))
That's elisp but I think those are standard lispy functions.
For all you haskellers out there, there is no need to twist your brains :)
(defun take (n l)
(subseq l 0 (min n (length l))))
(defun drop (n l)
(subseq l n))
(defun remove-nth (n l)
(append (take (- n 1) l)
(drop n l)))
My horrible elisp solution:
(defun without-nth (list n)
(defun accum-if (list accum n)
(if (not list)
accum
(accum-if (cdr list) (if (eq n 0) accum (cons (car list) accum))
(- n 1))))
(reverse (accum-if list '() n)))
(without-nth '(1 2 3) 1)
Should be easily portable to Common Lisp.
A much simpler solution will be as follows.
(defun remove-nth (n lst)
(append (subseq lst 0 (- n 1)) (subseq lst n (length lst)))
)