Jump to content

BlockName to variable


pBe

Recommended Posts

This routine will a assign a value to a variable with the same name as the block it counts I created this as a subroutine for a program that updates the Fields on a table. This would be my first attempt with the mapcar/Lambda function mixed with Vlisp codes. appreciate any comments and suggestions :)

Is it just me or its really less troublesome to filter selecton sets with good 'ol Lisp.... (vlax-safearray..... and the like is just too busy

 

(defun BlockName_to_variable ()
 (setq ol_blks (ssget "x" '((0 . "INSERT") (8 . "LayerName1,LayerName2")))
bn_lst (mapcar 'vlax-ename->vla-object
  (mapcar 'cadr (ssnamex ol_blks))
 )
 )
 (mapcar '(lambda (n)
     (if (not (member (vla-get-effectivename n) fnl_lst))
       (setq fnl_lst (cons (vla-get-effectivename n) fnl_lst))
     )
     (princ)
   )
  bn_lst
 )
 (mapcar '(lambda (x)
     (setq cnt 0)
     (foreach itm (mapcar 'vla-get-effectivename bn_lst)
       (if (= x itm)
  (set (setq dd (read itm)) (setq cnt (1+ cnt)))
       )
     )
   )
  fnl_lst
 )
 (foreach nmbr fnl_lst
   (print nmbr)
   (princ (eval (read nmbr)))
   (princ)
 )
)

 

Change the layer name filter to suit your needs

 

NOTE:

there are no error catch on this code.. so pardon if it crashes

Link to comment
Share on other sites

Hi pBe,

 

Your function is quite inefficient in that you are iterating through the same list of information a number of times, to improve efficiency, try to minimise the number of iterations:

 

(defun c:test ( / _assoc++ i ss e lst ) (vl-load-com)

 (defun _assoc++ ( key lst / pair )
   (if (setq pair (assoc key lst))
     (subst (cons key (1+ (cdr pair))) pair lst)
     (cons  (cons key 1) lst)
   )
 )

 (if (setq i -1 ss (ssget "_X" '((0 . "INSERT") (8 . "Layername1,Layername2"))))
   (progn
     (while (setq e (ssname ss (setq i (1+ i))))
       (setq lst (_assoc++ (vla-get-EffectiveName (vlax-ename->vla-object e)) lst))
     )

     (print lst)
   )
 )

 (princ)
)

You could set variables using the effective name and taking the value of the count from the resultant list, but I don't see this as a good way to handle the information.

Edited by Lee Mac
Link to comment
Share on other sites

It's really a shame that assoc and subst are such underused functions.

 

True - because they are pretty quick and quite elegant when used in situations that warrant their use - I think perhaps most users tend to restrict their usage to dealing with 'entget' list manipulation.

Link to comment
Share on other sites

True - because they are pretty quick and elegant when used in situations that warrant their use - I think perhaps most users tend to restrict their usage to dealing with 'entget' list manipulation.

Precisely.

Hell, until about 6-8 months ago, I had never used them for anything except with entget. I had something similar to this, I was wanting to calculate the area of each contour and return the total area for each elevation (had several contours for the same elevation - multiple stage pond with berm).

Link to comment
Share on other sites

Lee,

The part where you assign Variables is missing in your code which is the whole point of the routine.

 

Your function is quite inefficient in that you are iterating through the same list of information a number of times, to improve efficiency, try to minimise the number of iterations

 

You're right.. i idid go thru the same list more than once or twice

I originally wrote it this way...

 

(defun btv (/)
(setq  ol_blks (ssget "x" '((0 . "INSERT")(8 . "Layername1,Layername2"))) cnt 0 bn_lst nil)
         (while (< cnt (sslength ol_blks))
     (setq bn_lst (cons
            (vla-get-EffectiveName (vlax-ename->vla-object (ssname ol_blks cnt ))) bn_lst) cnt (1+ cnt))
    )

(foreach itm (LM:Unique  bn_lst) 
    (setq rslt (- (length bn_lst)(length (vl-remove itm bn_lst))))
        (set (setq dd (read itm)) rslt)
     (print itm)(princ (itoa rslt))(princ)
 )
  )

;;;;; Lee Mac 2010 ;;;;;
(defun LM:Unique ( l )
   (if l (cons (car l) (LM:Unique (vl-remove (car l) (cdr l)))))
  )

 

I even throw in your duplicate routine .. to which i found out is what they call Recursive programming,

 

I just thought of trying my hand with Lamda and mapcar maybe thats why it ended up like the way it did :D

 

It's really a shame that assoc and subst are such underused functions.

 

Come to think of it Alanjit, yeah you're right, i'll try to use it more often in the future

 

Now... whats the problem again ? :lol:

Link to comment
Share on other sites

The part where you assign Variables is missing in your code which is the whole point of the routine.

 

Yeah, I did actually make a note about that at the bottom of my post....

Link to comment
Share on other sites

I guess you did.. apologies Lee

 

(foreach itm [color=sienna](LM:Unique  bn_lst) ;;;;<--------[/color]
    (setq rslt (- (length bn_lst)(length (vl-remove itm bn_lst))))
        (set (setq dd (read itm)) rslt)
     (print itm)(princ (itoa rslt))(princ)
 )
  )

 

do you think that its a good idea to call the duplicate routine at this line?

does it run the LM:Unique code every after item on the list? should i just assigned a variable name for it? :?

Link to comment
Share on other sites

You can see the order of evaluation using the 'animate' utility in the VLIDE - it will highlight each statement as it is evaluated.

 

You could use something like this to test:

 

(defun sub ( / l )
 (foreach x '(1 2 3 4 5 6 7 8 9)
   (setq l (cons x l))
 )
 (reverse l)
)

(defun main nil
 (foreach x (sub)
   (print x)
 )
 (princ)
)

You should find that the 'sub' function is only evaluated once, then foreach operates on each element of the list supplied to it by 'sub'.

 

Anyway, back to your code... I see what you are trying to achieve and your code, as it stands, should work; but if you want my suggestions, there are a few ways you could improve its efficiency:

 

You are currently running 3 passes of the information: 1) Get list of block names 2) Remove duplicates from this list 3) Get/set variable to block count

 

You could quickly reduce this to 2 passes by detecting duplicates in the first pass hence:

 

(while (< cnt (sslength ol_blks))
   (if (not (member (setq n (vla-get-EffectiveName (vlax-ename->vla-object (ssname ol_blks cnt))))))
     (setq bn_list (cons n bn_list))
   )
 )

But of course, this would have an effect on your later method to list the occurences of each block.

 

Another way to reduce the number of passes is to combine the functions to create a unique list and list the occurrences, perhaps something like this:

 

(defun LM:ListOccurrences ( lst )
 ;; © Lee Mac 2010
 (if lst
   (cons
     (cons (car lst)
       (- (length lst) (length (vl-remove (car lst) lst)))
     )
     (LM:ListOccurrences (vl-remove (car lst) lst))
   )
 )
)

However, I still think your best option is the method used by my code above in which the list is passed once to retrieve the blocks/counts.

 

If you really wanted to set the variables, you could use something like this on the result (of course, we are back to 2 passes):

 

(mapcar '(lambda ( pair ) (set (read (car pair)) (cdr pair))) <result>)

I suppose to combine everything into one, single pass, you could use something like this:

 

(defun c:test ( / i ss e n ) (vl-load-com)

 (if (setq i -1 ss (ssget "_X" '((0 . "INSERT") (8 . "Layername1,Layername2"))))
   (progn
     (while (setq e (ssname ss (setq i (1+ i))))
       (setq n (read (vla-get-EffectiveName (vlax-ename->vla-object e))))

       (set n (cond ((eval n) (1+ (eval n))) ( 1 )))
     )
   )
 )

 (princ)
)

But then you would have to remember to localise all those dynamically created variables too, else you will get erroneous results on the second pass...

 

As I said, I much prefer list manipulation - after all, that is what LISP was designed for.

 

Lee

Link to comment
Share on other sites

 

(defun LM:ListOccurrences ( lst )
;; © Lee Mac 2010
(if lst
(cons
(cons (car lst)
(- (length lst) (length (vl-remove (car lst) lst)))
)
(LM:ListOccurrences (vl-remove (car lst) lst))
)
)
)

 

Recursive programming :sweat:

Difficult... so difficult....

 

Thanks for the codes Lee... I'll save it on my LeeMac_Made_Me_Understand folder :thumbsup:

Link to comment
Share on other sites

Recursive programming :sweat:

Difficult... so difficult....

 

Ah - its only practice :)

 

Thanks for the codes Lee... I'll save it on my LeeMac_Made_Me_Understand folder :thumbsup:

 

You're welcome - did you understand what I was saying about the number of passes? if there is anything you don't understand just ask.

Edited by Lee Mac
Link to comment
Share on other sites

did you understand what I was saying about the number of passes? if there is anything you don't understand just ask.

 

 

Yes, now i understand.. the Animate tool from VLIDE showed me how many times it process the list... never use any of them tools before, i used to write my codes using Q.EXE DOS mode to check parenthesis matching. and sometimes just plain old notepad. i went over some of the codes i wrote before.. cheese and rice.. most of them are a memory hog... neat tool Animate

 

reading thru your codes made me aware about a lot of functions i ignored in the past i.e eval, lambda, apply... i tend to stay away from them, maybe because i'm too lazy to study it :) but you showed me how powerful this functions are..

 

Thank you Lee/Allan

 

Really grateful for this Forum :thumbsup:

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...