Updating list

Updating list

Ranjit_Singh
Advisor Advisor
895 Views
11 Replies
Message 1 of 12

Updating list

Ranjit_Singh
Advisor
Advisor

I have a list of real numbers (going upto 5 decimals). I want to run through the list and check every element to the previous one and if they match then increment the element (n + 1) by 0.00001 over element n, so they are different. Here is my code

(setq x 1)
(setq y (length lst1))
(while  (< x y)
(if (= (- (nth x lst1) (nth (- x 1) lst1)) 0)
(progn
(setq lst1 (subst (+ 0.00001 (nth x lst1)) (nth x lst1) lst1))
(setq x (+ x 1)))
(setq x (+ x 1))))

 

Nothing seems to change. I retrieve the values using rtos upto 6 decimals and nothing changes. What is going wrong? Thanks in advance.

0 Likes
896 Views
11 Replies
Replies (11)
Message 2 of 12

Kent1Cooper
Consultant
Consultant

For me, things do change, BUT:

 

I started with:

 

(setq lst1 '(1 1 2 3 4 4 5))

 

I pasted your code in, and lst1 ended up as:

 

(1.00001 1.00001 2 3 4.00001 4.00001 5)

 

because (subst) replaces all instances of the same value, not just the one in the position you ask for.  You'll need to go about it differently, perhaps by breaking the list into two pieces each time, changing the value in one of them, and re-assembling.

 

But apart from that problem, if nothing is changing at all for you, are you sure you're starting with a list saved to exactly the same variable name?  [I got confused at first between the number 1 and lower-case L.]

 

EDIT:  So I was thinking about how to go about it, and came up with another question.  I was going to do something that would use a PRE list and a POST list.  It would compare two adjacent items in the list, add the first one into the PRE list and make the rest into the POST list, and if those two are equal, up the value of the first one in the POST list.  Then do it again with the new POST list, etc.  But might you ever have three or more items in a row of the same value?  My approach would result in the second one being raised, but then that would no longer be equal to the third [or beyond], so the third would not get raised by twice the amount as I expect you would want.  Is that a condition that should be accounted for?

Kent Cooper, AIA
0 Likes
Message 3 of 12

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:

.... (subst) replaces all instances of the same value, not just the one in the position you ask for.  ....  But might you ever have three or more items in a row of the same value?  My approach would result in the second one being raised, but then that would no longer be equal to the third [or beyond], so the third would not get raised by twice the amount as I expect you would want.  Is that a condition that should be accounted for?


FURTHER EDIT [ran out of time to do it in the previous Reply]:  That turns out to be a good reason to use (subst), on the POST list.  Try this:

 

(defun ListDifferentiate (lst / pre post)
  (repeat (1- (length (setq post lst)))
    (setq
      pre (append pre (list (car post)))
      post (cdr post)
    ); setq
    (if (= (last pre) (car post))
      (setq post (subst (+ (car post) 1e-5) (car post) post))
    ); if
  ); repeat
  (setq lstdiff (append pre post))
); defun

It leaves the differentiated list in the lstdiff variable, for further use if needed.

 

Usage:

 

Command: (listdifferentiate '(1 1 2 2 2 3 4 5 5 6))

results in:
(1 1.00001 2 2.00001 2.00002 3 4 5 5.00001 6)

 

or with multiple same values at the end:

 

Command: (listdifferentiate '(1 1 2 2 2 3 4 5 5 6 6 6))

results in:
(1 1.00001 2 2.00001 2.00002 3 4 5 5.00001 6 6.00001 6.00002)

 

Kent Cooper, AIA
0 Likes
Message 4 of 12

Ranjit_Singh
Advisor
Advisor

Thanks! I checked my posted code and you are right. The code is doing what it is suppoed to. But when I run it as part of my LISP routine (much larger code) I get an error saying

; error: bad argument type: (or stringp symbolp): nil

 

My code basically is written in 2 parts.

First part reads a text file and generates a LIST of required elements (bunch of real numbers).

Second part takes above generated list and checks for duplicates (strictly next to each other; if 2 duplicates are separated by a number then I dont need to catch that, so my above code works fine).

 

But that second part code never comes into play because after the list is generated from the first part of the code the above error happens (; error: bad argument type: (or stringp symbolp): nil) and the remaing code (to clean duplicates) does not run and so my numbers aren't getting updated.

 

Can you help me with the above error? Basiclly I am using nil to check for end of file. Is that causing a problem? If so, how do I check for end of the text file as I dont want my code to go into indefinite loop. Thanks.

0 Likes
Message 5 of 12

Satoews
Advocate
Advocate

Have you tried debugging your code in the visual lisp ide in autocad? 

 

Tutorial into debugging

 

Pretty simple and it will show you where it is getting that error.

Shawn T
0 Likes
Message 6 of 12

Kent1Cooper
Consultant
Consultant

@Ranjit_Singh wrote:

.... I get an error saying

; error: bad argument type: (or stringp symbolp): nil

.... 

Can you help me with the above error? ....


[Not without seeing the rest of the code....]

Kent Cooper, AIA
0 Likes
Message 7 of 12

Ranjit_Singh
Advisor
Advisor

Thanks evevryone for the help. I was able to get rid of the error and everything works smoothly. I have succesfully generated the 2 lists that I need. Now I am writing it out to a new text file. Here is the code basically taking nth term from each list and writing it out to stafiletxt

(setq stafiletxt (open "C:/Users/Default/AppData/Local/Temp/stafiletxt.txt" "w"))
(setq n 0)
(repeat (length stalst)
(prin1 (type stafiletxt))
(write-line (strcat (rtos (nth n stalst) 2 5) " " (rtos (nth n stalst2) 2 5)) stafiletxt)
(setq n (+ n 1)))
(close stafiletxt)

Question is I dont like the static path at the top. At the begining of my code the user is asked to choose the original text file using the below code 

 

(setq stafile (open (setq stafilepath (getfiled "Select file" "H:/" "txt" 10)) "r"))

The user is directed to H drive but can navigate through the explorer window anywhere and pick the text file. This filepath is then captured in stafilepath. How can I pass this path for creating stafiletxt. I tried using this but it does not work

 

(setq stafiletxt (open stafilepath "w"))
0 Likes
Message 8 of 12

Kent1Cooper
Consultant
Consultant

If I'm interpreting correctly, you appear to be trying to open for writing the same file that you are already have open for reading [unless there is other code in between that you've omitted].  Try closing it first, and then opening it for writing [or appending], or perhaps just opening it for writing or appending in the initial (getfiled) part.

Kent Cooper, AIA
0 Likes
Message 9 of 12

Ranjit_Singh
Advisor
Advisor

Hi Kent, thanks for the prompt response. No, I am not tryng to overwrite the same file. I start code by opening a text file using

(setq stafile (open (setq stafilepath (getfiled "Select file" "H:/" "txt" 10)) "r"))

Then I process the text file (which is not necessarily in H drive but wherever the user selects it) and generate two lists and close this original text file and then write out the 2 lists to stafiletxt.txt using

 

(setq stafiletxt (open "C:/Users/Default/AppData/Local/Temp/stafiletxt.tx​t" "w"))
(setq n 0)
(repeat (length stalst)
(prin1 (type stafiletxt))
(write-line (strcat (rtos (nth n stalst) 2 5) " " (rtos (nth n stalst2) 2 5)) stafiletxt)
(setq n (+ n 1)))
(close stafiletxt)

I dont want the original file to be replaced. I want to create a new file in the same directory where the original was selected, maybe with a different name. I dont know how to do it and so I am providing a static path C:/Users/Default/AppData/Local/Temp/stafiletxt.tx​t.

 

 

For instance when I run the very first code (setq stafile (open (setq stafilepath (getfiled "Select file" "H:/" "txt" 10)) "r")) at autocad prompt  it allows me to select a file. Lets say I browse to G:\2010\10-0022 and pick 1234.txt then my lisp stores the path in stafilepath as "G://2010//10-0022//1234.txt" How can I now edit my lisp to create a new file at G:\2010\10-0022 named 1234txt.txt?

0 Likes
Message 10 of 12

dbroad
Mentor
Mentor

Looks like Kent has given you great help.  If you are sure that the list is increasing numerical order, then this could also give similar results.  Ths function name is arbitrary.

 

(defun foo (lst / a)
  (cons
  (setq a (car lst))
  (mapcar '(lambda (x)
	     (setq a
		    (if (<= x a)
	                (+ a 0.00001)
		        x)))
	  (cdr lst))))
Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 11 of 12

Kent1Cooper
Consultant
Consultant

As a start, read Help about the (getfiled) function, and see whether any of the flags argument values will help you get what you want.  I haven't dug deeply, but there are some promising-looking choices there.

Kent Cooper, AIA
0 Likes
Message 12 of 12

Ranjit_Singh
Advisor
Advisor

Hi Kent, that helped a lot. I have the LISP working as I should. Thanks everyone. One last question. When the LISP goes through it leaves echo of FILE several times (essentially because it is writing it so many times). Is there anyway to turn this echo off? I turned off cmdecho and set nomutt to 1. But it doesn't help.

0 Likes