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).
Related
When I was trying to check the number is equal to any element in list, I get the following error:
'NIL' is not of the expected type 'NUMBER'
(defun check-num (li n)
(cond
((= n (car li)) t)
((not (= n (car li))) (check-num (cdr li) n))
((not (= n (car li))) nil)))
(check-num '(1 2 3 4 5) 6)
I found that the problem occur when it try to excute the function 'check-num' with the empty list with the number entered after perform all checking.
The error come out when the compiler try to perform the following function:
(check-num nil 6)
The immediate problem is that you never check for the end of the list. The car of the empty list is nil again. = compares numbers. Nil is not a number.
Check for the end of the list first. Some minor stylistic issues: when using conses as a list, use first and rest instead of car and cdr, name things as they are (list), use proper formatting.
(defun check-num (list n)
(cond ((endp list) nil) ; <-
((= (first list) n) t)
(t (check-num (rest list) n))))
However, it should be noted that there are several ways already in the standard to achieve this check, e. g.:
(member n list)
(find n list)
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.
I am pretty new to Racket. I am trying to write a program to return an index element in the list else, return the entire list. I have two separate methods: One recursive method to give index elements of the list if present else give the entire list. However, calling one method from the other is giving me error. Can someone please guide me how I can change this program to give me the whole list if none of the index elements are present? For example this call should give me the entire list
(get-nth 2 '(a b)) ; ==> a b
#lang racket
(define get-nth
(lambda (index lst)
(if (= index 0) ; when index is zero
(car lst) ; return the first element
(get-nth (- index 1) ; else recurse with the decrement of index
(cdr lst))))) ; and all but the first element (the rest) of lst
;; test
Thanks in advance,
For this to work, you'll have to store the original list somewhere. To avoid unnecessary helper functions, we can use a named let to implement iteration and leave alone the original lst for the case when we have to return it. And of course, we have to test for the case when we run out of elements because the given index is outside the list. This is what I mean:
(define get-nth
(lambda (index lst)
(let loop ((index index) (my-list lst))
(cond ((null? my-list) lst)
((= index 0) (car my-list))
(else (loop (- index 1) (cdr my-list)))))))
For example:
(get-nth 0 '(a b))
=> 'a
(get-nth 2 '(a b))
=> '(a b)
I have two lists as follows:
(x y z) & (2 1)
and I want to have a result like:
((x y) (z))
The relation of the lists is quite clear. So basically I want to rearrange the members of the first list into a list of lists with two (length of second list) lists.
I have tried running two dotimes iterations to do this:
(let ((result) (list1* list1))
(dotimes (n (length list2) result)
(progn (setq result
(append result
(list (let ((result2))
(dotimes (m (nth n list2) result2)
(setq result2
(append result2
(list (nth m list1*)))))))))
(setq list1*
(subseq list1* 0 (nth n list2))))))
The idea is that I make the first list of the expected result (x y), and then I want to update the (x y z) list so that the x any y are removed and I only have (z). Then the loop runs again to get the (z) list in the expected result. This does not work correctly and results in:
((x y) (x))
which means apparently the second command for progn which is basically updating the list1* is not working. Clearly there must be a correct and better way of doing this and I was wondering whether anyone can help with this. Also explain why it is not possible to have the solution explained?
If I see that right, your problem is in (subseq list1* 0 (nth n list2)), which returns the part of the list that you do not want.
I have the following to offer:
(defun partition-list (list lengths)
(mapcar (lambda (length)
(loop :repeat length
:collect (pop list)))
lengths))
This is a bit simplistic, of course, as it does not handle unexpected input, such as (length list) being smaller than (reduce #'+ lengths), but it can be expanded upon.
Just for the sake of example, an alternative using iterate:
(defun partition-list (list by)
(iter:iter
(iter:for element in list)
(iter:for i from 1)
(iter:generating measure in by)
(iter:collect element into sublist)
(when (= (or measure (iter:next measure)) i)
(iter:collect sublist)
(iter:next measure)
(setf i 0 sublist nil))))
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)