Serabis Posted December 10, 2012 Posted December 10, 2012 (edited) Hello all! So I am fairly new at lisp, and I know only a little bit about lists in lisp, but I need to create a list through a while loop. The problem I have is that I use the same variable each time I want to add to the list, which causes the list to never be larger than one. I'm guessing this is some pointer issue, and I was wondering what a work around is. Here is some sample code: (defun listcopy (list1) (setq index1 0) (setq listlength 10) (setq newlist '()) (while (< index1 listlength) (setq current (nth index1 list1)) (setq newcurrent (substr current 5)) (insertnth newcurrent index1 newlist) (1+ index1) );end while );end function (defun insertnth (element num list1) (if (and list1 (< 0 num)) (cons (car list1) (insertnth element (1- num) (cdr list1))) (cons element list1) );end if );end function This is a simplified version of the code: I am actually doing a lot more than just taking the first 5 letters off of the string, but this serves as a good example. Thanks for any help! Edited December 10, 2012 by Serabis Quote
bgingerich Posted December 10, 2012 Posted December 10, 2012 Try adding the following code after "(insertnth..." (1+ index1) One suggestion. Change the ( Quote
Serabis Posted December 10, 2012 Author Posted December 10, 2012 Good catch, but after looking at my "actual" code, I had that in there, so thats not the problem -_- Quote
pBe Posted December 11, 2012 Posted December 11, 2012 .... [b](setq newlist [/b](insertnth newcurrent index1 newlist)[b])[/b] [b](setq index1[/b] (1+ index1)[b])[/b] ... Quote
Lee Mac Posted December 11, 2012 Posted December 11, 2012 As pBe has correctly indicated, the problem is because you are not assigning the return of your insertnth function, or the 1+ function to your variables. However, your task could be performed using just: (mapcar '(lambda ( x ) (substr x 5)) list1) Also, remember to Localise your Variables. Quote
irneb Posted December 11, 2012 Posted December 11, 2012 Also if you still want to use the imperative looping (i.e. not yet understanding the functional as per Lee's), I'd advise simply adding to the front of the new list using cons then do a reverse at the end. This would be a lot more efficient than using that insertnth. E.g. (defun listcopy (list1 / result) (foreach item list1 (setq result (cons (substr item 5) result))) (reverse result)) Or alternatively loop from the last item downwards:. (defun listcopy (list1 / result index) (repeat (setq index (length list1)) (setq result (cons (substr (nth (setq index (1- index)) list1) 5) result))) result) Quote
Serabis Posted December 12, 2012 Author Posted December 12, 2012 Thank you all! All your implementations work well. Quote
irneb Posted December 13, 2012 Posted December 13, 2012 Thank you all! All your implementations work well.Glad to help. One thing to remember with lisp (especially AutoLisp) lists are implemented as Linked Lists. So an index to somewhere in the middle of the list takes time to get to, it has to run through from the start (or alternatively the end of the list if it's implemented as a Doubly Linked List) - other than when using an array in other languages. Thus the most efficient way would be to design your program to try and ignore the index itself - i.e. simply run through the list and modify each item (as Lee's code does). Quote
Serabis Posted December 14, 2012 Author Posted December 14, 2012 Ah I see. To better explain my situation though, I needed to take a list filled with all the .dwg files in a directory, use a parsing algorithm to extract an integer from the text string, and then use that integer to decide whether or not to include it into a new list of "desirable" drawing names. Thus, I feel that maybe instead of using InsertNth to insert into a new list, maybe a better implementation could use some function RemoveNth so that when I find an "undesirable" element in the list, I could remove it, thus avoiding creating a new list in the process. Quote
irneb Posted December 18, 2012 Posted December 18, 2012 You can use the vl-remove function, but it's inefficient. In your case I'd go with a vl-remove-if-not function. Say you want to test for an integer (defun Only<100 (fileNames /) (vl-remove-if-not '(lambda (path / num) (and (setq num (substr (vl-filename-base path) 1 4)) (not (wcmatch num "*[~0-9]*")) (< (itoa num) 100))) fileNames)) Notice it's still only running through the list once - no need to use an index. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.