TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Hangman on May 26, 2010, 12:17:53 PM
-
Okay, I give up. I've been searching the database and the help file for a way to pull the items of a list and put them into a string for display.
My initial thought was to use 'Length' to get the number of layers listed, then create a bunch of variables to put each layer in:
(setq LayrLength (length GV_LayersOff))
(setq L-a (nth 0 GV_LayersOff)
L-b (nth 1 ...
-but realized this isn't going to work. I guess if I could figure out how to make a variable for each item in the list, but this would be horrendous just to display the layers that are currently off.
I have an ALERT that I want to display to the users:
(ALERT (strcat "The following Layers are currently Off: \n" GV_LayersOff))
-where GV_LayersOff is a list of current layers off; from here:
...
(setq LayrInfo (tblnext "Layer" 'T)) ; set variable to first layer (zero)
(while LayrInfo
(setq LayrName (cdr (assoc 2 LayrInfo)) ; get layer name
LayrColr (cdr (assoc 62 LayrInfo)) ; get layer color
LayrInfo (tblnext "Layer") ; set variable to next layer
)
(if (minusp LayrColr) ; if layer color is negative,
(setq GV_LayersOff (cons LayrName GV_LayersOff)) ; the layer is off, add to list.
)
); while
...
I would prefer to display to the users something like this:
The following Layers are currently Off:
Layer_1
Layer_2
Layer_3
Layer_4
But at the moment, I'd be happy just to get the List into a string.
I have found many comments regarding how easy it is, but no code to use as an example. I've searched the help file but haven't stumbled upon anything yet. What's frustrating is something I thought would be easy has turned into two hours of research and still have not gotten anywhere.
Will you help me please?. Thanks.
-
Here are two for you to play around with :-)
(defun lst->str ( lst del )
(if (cdr lst)
(strcat (car lst) del (lst->str (cdr lst) del))
(car lst)
)
)
(defun lst->str ( lst del )
(
(lambda ( str )
(foreach x (cdr lst)
(setq str (strcat str del x))
)
str
)
(car lst)
)
)
-
The entire thread is educational, but it goes from string->list to list->string at this point.
http://www.theswamp.org/index.php?topic=32845.msg383391#msg383391
Nice submissions Lee. :)
-
Thanks Alan, I agree - that is a great thread for someone who's learning ;-)
-
The entire thread is educational, but it goes from string->list to list->string at this point.
http://www.theswamp.org/index.php?topic=32845.msg383391#msg383391
...
Yes Alan, it is. That was one of those I read over and over again for the last hour trying to comprehend it.
I need to put out a thought request for you guys here, and I know it'll drive you nuts, but it really helps us in learning how and why you are using certain functions in certain places. If you would please put comments after each line of code, it would really help. ^-^
Thank you Lee, I will disect these and see what I can understand. I still have trouble with 'Lambda', I'm not yet comprehending the implications of such a powerful tool nor its position in the code.
-
As a quick explanation, lambda is an anonymous function, in this case taking one argument. It is used in places where defining a whole subfunction for a simple task seems a bit redundant. The lambda function makes things convenient, in this case, I don't have to define the variable 'str' before entering the foreach loop - I can just feed it the value through the lambda function.
As another quick example of it being used in this way:
(if (setq ss (ssget))
(
(lambda ( i / lst )
(while (setq ent (ssname ss (setq i (1+ i))))
(setq lst (cons ent lst))
)
lst
)
-1
)
)
Notice here also, it is a convenience, as we don't need to have (setq i -1) before the while loop.
As for the comments - I'm probably the world's worst for commenting - I don't think I use any at all. I know this is probably considered bad practice, but to be perfectly honest, when reading code, I find comments distracting and sometimes even misleading - I prefer to interpret the code myself.
-
Hi Hangman,
I know this is really answering your question, but if you have maybe 200+ layers in your drawing that are turned off,
it's going to be an awful big alert box!!
But I hear what you are saying about list to string. I am having difficulty with it myself.
Thanks for the link and the example Alan and Lee.
A nice little bit of homework.
For what its worth, here is what I use to print to the textscreen, and if you want you could use the following line for the alert
(alert "\nPress F2 to see list of layers that are OFF")
(defun c:LayerListoff (/ LayerTable LayerOffList)
(vl-load-com)
(setq LayerTable (vla-get-layers (vla-get-activedocument (vlax-get-acad-object))))
(vlax-for LayerName LayerTable
(if (= (vla-get-layeron LayerName) :vlax-false)
(progn (setq LayerOffList (acad_strlsort (cons (vla-get-name LayerName) LayerOffList)))
(princ (strcat "\n" (vla-get-name LayerName) " is turned OFF."))
)
)
)
(princ (strcat "\n" (itoa (length LayerOffList)) " Layers are turned OFF."))
(setq LayerOffList nil)
(princ)
)
-
You could always vl-princ-to-string the list, then alert it. LoL
-
You could always vl-princ-to-string the list, then alert it. LoL
Classic! :-D
-
But I hear what you are saying about list to string. I am having difficulty with it myself.
If it helps at all, I would think about it like this: You need a string to start with, whether it be an empty string ( "" ) or something else, you need a string, as you are, with every item in the list, setting the output to itself + the new item.
(foreach x '("1" "2" "3" "4" "5")
(setq str (strcat str x))
)
If 'str' were nil before the loop, we would have an error, as (strcat nil "1")
is not valid.
So say, we set 'str' to an empty string:
(setq str "")
(foreach x '("1" "2" "3" "4" "5")
(setq str (strcat str x))
)
Now, with every item, the value of str will be:
x = "1", str = "1"
x = "2", str = "12"
x = "3", str = "123"
etc
We can use this method with a delimiter if need be:
(setq str "")
(foreach x '("1" "2" "3" "4" "5")
(setq str (strcat str x ","))
)
Notice that in this way we receive:
str = "1,2,3,4,5,"
And we have a trailing delimiter on the end - so we can get around this by setting the value of 'str' to the first element in the list instead of the empty string, and iterating through the rest of the list with the delimiter between the existing 'str' and new value:
(setq str "1")
(foreach x '("2" "3" "4" "5")
(setq str (strcat str "," x))
)
x = "2", str = "1,2"
x = "3", str = "1,2,3"
etc
Of course, this is a specific example - so we can replace "," with a variable denoting the delimiter, and use list operations on the list of items:
(setq lst '("1" "2" "3" "4" "5"))
(setq str (car lst) del ",")
(foreach x (cdr lst)
(setq str (strcat str del x))
)
I hope this clarifies things a bit better,
Lee
-
Hi Hangman,
I know this is really answering your question, but if you have maybe 200+ layers in your drawing that are turned off,
it's going to be an awful big alert box!!
...
For what its worth, here is what I use to print to the textscreen, and if you want you could use the following line for the alert
(alert "\nPress F2 to see list of layers that are OFF")
...
Oh, good advice John, I didn't even think of that. I hope we don't have 200+ layers off, but you never know.
...
As for the comments - I'm probably the world's worst for commenting - I don't think I use any at all. I know this is probably considered bad practice, but to be perfectly honest, when reading code, I find comments distracting and sometimes even misleading - I prefer to interpret the code myself.
I understand Lee. I try to put in the comments, but I find myself interpreting the code rather than just reading my own comments. I think it is good practice to interpret the code, keeps the mind busy, but as I mentioned, for those of us not familiar with where the line of code is going, it's difficult to interpret. Especially when you have a piece of code like 'lambda'. When we go to the help file for the definition, its somewhat eluding because there are so many applications. It makes it difficult to fully understand the use of it.
Anyway, enough on that one. I thank you for the explanation.
-
Lee already posted a great explanation, but I wrote this and got sidetracked, so I'm posting it anyway...
(defun foo (lst del / str)
(setq str (car lst)) ; set string based on first item of list
(foreach x (cdr lst) ; step through list (except first item, since we alreaded appended it to your string
(setq str (strcat str del x)) ; append 'next' item in list to string (separated with deliminator)
)
)
-
I hope this clarifies things a bit better
Cheers Lee,
That sheds some light on the subject.
I'll have to look at it in more detail tomorrow as I have to get out of this place!! :-D
-
...
If it helps at all, I would think about it like this: You need a string to start with, whether it be an empty string ( "" ) or something else, you need a string, as you are, with every item in the list, setting the output to itself + the new item.
(foreach x '("1" "2" "3" "4" "5")
(setq str (strcat str x))
)
If 'str' were nil before the loop, we would have an error, as (strcat nil "1")
is not valid.
So say, we set 'str' to an empty string:
...
This is EXACTLY where I was getting hung up too. I didn't understand I needed a string first. I WAS setting my list to an undefined variable and it kept erroring on me.
THANK YOU Lee for this magnificent explanation.
-
Lee already posted a great explanation, but I wrote this and got sidetracked, so I'm posting it anyway...
(defun foo (lst del / str)
(setq str (car lst)) ; set string based on first item of list
(foreach x (cdr lst) ; step through list (except first item, since we alreaded appended it to your string
(setq str (strcat str del x)) ; append 'next' item in list to string (separated with deliminator)
)
)
Now this is good stuff. I interpret the last line differently, I see this:
(setq str (strcat str del x))
as setting the variable 'str' and appending to it with 'str', but deleting 'x', so you would end up with a result like this: (if 'lst' had 'Layer-1', 'Layer-2', 'Layer-3', 'Layer-4')
Layer-1 Layer-1 Layer-1 Layer-1
Simply because there is no 'del' definition in the help file. What is it, where did you get it, etc.
I would think the code would have to read like this:
(setq str ((strcat str) del x))
in order to get what you described, but appearently not.
Thank you for the notes Alan.
-
'del' is an argument for the function.
del = delimiter, as in my explanation :-)
-
'del' is an argument for the function.
del = delimiter, as in my explanation :-)
:lmao: :lmao:
My mind was clearly somewhere else. I called it deliminator in my explanation. :ugly:
-
'del' is an argument for the function.
del = delimiter, as in my explanation :-)
:lmao: :lmao:
My mind was clearly somewhere else. I called it deliminator in my explanation. :ugly:
That does sound cooler :lol:
-
'del' is an argument for the function.
del = delimiter, as in my explanation :-)
:lmao: :lmao:
My mind was clearly somewhere else. I called it deliminator in my explanation. :ugly:
That's what I interpreted, 'del' for delete or deliminator. :D
-
'del' is an argument for the function.
del = delimiter, as in my explanation :-)
:lmao: :lmao:
My mind was clearly somewhere else. I called it deliminator in my explanation. :ugly:
That does sound cooler :lol:
It travels back in time and delimits all John and Sarah Connor's text.
-
Just something I was considering ... several options are available, but they don't give you the option to add a delimiter, unless of course you use lambda or some other equally useful function ... i.e.
(defun list->string (mylist)
(apply 'strcat mylist)
)
(defun list->string (mylist delim)
(setq str (car mylist))
(vl-every '(lambda (x) (setq str (strcat str delim x))) (cdr mylist))
str
)
The second bit of code, while not nearly as concise, allows the addition of delimiters.
To further expand the code, one might do a check for numerical values and convert them explicitly to strings ... that will likely require a bit of code to check for various situations, but as long as the type is going to be string, it may not be required.