Jump to content

Recommended Posts

Posted (edited)

Alright folks,

 

A few months ago I wrote a data collection program for one of the councils which basically read scraped all the blocks in x amount of drawings and store the information in a MS access database. This got me thinking is it worth removing an item from an array after it is matched to a an item from a list using simple iteration. For example

;For the sake of the discussion topic imagine vl-sort doesn't exist
(setq BlockList(list 
[List of block objects from the block table]))
(setq modelSpaceBlocks (list [<x> All blocks within modelspace]))
(vlax-for BlockListc
 (setq i -1)
 (while (< (setq i(1= i))(length modelSpaceBlocks))
   (if(equals (vla-getName c)(vla-getName (nth i modelSpaceBlocks))
     (progn
       ;Do something with the block
       ;-------------------- Include or leave out? --------------
        (vl-remove (nth i modelSpaceBlocks) modelSpaceBlocks)
       ;----------------------------------------------------------
     )
   )
 )
)

Perhaps not the best example but surely there must be a point where the value of x is high enough that iterating through it each time. It may be the case that the first 500 blocks remove slow the program down but gradually as the list is reduced in size the process wouldn't be comparing against redundant blocks. Any one have any thoughts on the subject or better yet has anyone ran a comparison?

 

SOliver.

Edited by SOliver
erroneous line of code
  • Replies 21
  • Created
  • Last Reply

Top Posters In This Topic

  • SOliver

    8

  • alanjt

    5

  • Lee Mac

    5

  • BlackBox

    4

Top Posters In This Topic

Posted

I'd be more concerned about you stepping through the same modelSpaceBlocks list each type you get to a new item in BlockListc.

When you step through BlockListc, just check if it's name is a member (or vl-position) of a pre-stepped through modelSpaceBlocks list that's comprised of nothing but names (mapcar 'vla-get-name modelSpaceBlock).

Posted
I'd be more concerned about you stepping through the same modelSpaceBlocks list each type you get to a new item in BlockListc.

When you step through BlockListc, just check if it's name is a member (or vl-position) of a pre-stepped through modelSpaceBlocks list that's comprised of nothing but names (mapcar 'vla-get-name modelSpaceBlock).

 

Removed the i equal list length - wasn't meant to be there.

 

Mapcar would certainly be a more suitable setup that what is there, I spend far too much time with php lol.

 

Don't suppose you could provide an example of how you would implement vl-position?

Posted

Snippet based on your above provided code (in this situation, member is the same, vl-position just happens to be a tiny bit faster).

 



(setq modelSpaceBlocks (mapcar 'vla-getName modelSpaceBlocks))

;; STUFF

(if (vl-position (vla-getName c) modelSpaceBlocks)
   ;; DO STUFF
)

Posted

 

AutoLISP Reference Guide > AutoLISP Functions > V Functions >

 

vl-position

 

Returns the index of the specified list item

 

(vl-position [i]symbol list[/i])

 

Arguments

 

symbol

Any AutoLISP symbol.

 

list

A true list.

 

Return Values

 

An integer containing the index position of symbol in list; otherwise nil if symbol does not exist in the list.

 

Note that the first list element is index 0, the second element is index 1, and so on.

 

Examples

_$ [i](setq stuff (list "a""b" "c" "d" "e"))[/i]
("a" "b" "c" "d" "e")
_$ [i](vl-position "c" stuff)[/i]
2

 

Meaningless text so I can make this post.

Posted
Snippet based on your above provided code ...

 

Just curious; perhaps I'm missing something....

 

I'd think it a duplication of work to step through a block collection, saving the Vla-Objects to a list (modelSpaceBlocks), only to use (mapcar 'vla-get-name modelSpaceBlocks) to get a list of block names... instead, would this not be simpler:

 

(if (setq ss (ssget "_x" (list '(0 . "INSERT") (cons 410 (getvar 'ctab)))))
   (progn
     (vlax-for x (setq ss
                    (vla-get-activeselectionset
                      (vla-get-activedocument (vlax-get-acad-object))))
       (if (not (vl-position (setq n (vla-get-name x)) blockList))
         (setq blockList (cons (vla-get-name x) blockList))))
     (if (vl-position "[color=red]blockName[/color]" blockList)
       [color=seagreen];; do something
[/color]        )
     (vla-delete ss)))

Posted (edited)

Ah I see what you're gettin' at I think: Run through the list once to gather the names and then use vl-position as a replace meant for the double vla-get-name?

 

I suppose what might be a good idea is to create a list of lists for each block name and store the indices in each list for example:

#
(setq BlockIndices (list
 ("sampleBlockName" 1 25 40)
 ("otherBlock" 3 5 7)
))

And use vla-item to pick items as the BlockList iterates

 

Above would mean the modelSpaceBlocks list will have an equal number (or less) items as the blockList. Which would be follwed with something like:

 (vlax-for c BlockList
    (setq i -1)
    (while (< )setq i(1+ i))(length blockIndices))
      (if(equal (vla-get-name c)(nth i (car blockIndices))
       (progn
        (someFunction(mapcar 
          '(lambda(y)(nth x modelSpaceBlocks )) (cadr modelSpaceBlocks) )
         (setq i (length blockIndices))
     )
   )
 )

There would only be one comparison of the names and then mapcer to pick them up

Edited by SOliver
Extension, erroneous line of code
Posted
Just curious; perhaps I'm missing something....

 

I'd think it a duplication of work to step through a block collection, saving the Vla-Objects to a list (modelSpaceBlocks), only to use (mapcar 'vla-get-name modelSpaceBlocks) to get a list of block names... instead, would this not be simpler:

 

(if (setq ss (ssget "_x" (list '(0 . "INSERT") (cons 410 (getvar 'ctab)))))
   (progn
     (vlax-for x (setq ss
                    (vla-get-activeselectionset
                      (vla-get-activedocument (vlax-get-acad-object))))
       (if (not (vl-position (setq n (vla-get-name x)) blockList))
         (setq blockList (cons (vla-get-name x) blockList))))
     (if (vl-position "[color=red]blockName[/color]" blockList)
       [color=seagreen];; do something
[/color]        )
     (vla-delete ss)))

More than likely, but I based on the information provided, that was the best I could come up with. Not sure why he would have other lists.

Posted
More than likely, but I based on the information provided, that was the best I could come up with. Not sure why he would have other lists.

 

No worries, you were explicit about providing an example based on the OP's code.

 

Ah I see what you're gettin' at I think: Run through the list once to gather the names and then use vl-position as a replace meant for the double vla-get-name?

 

I suppose what might be a good idea is to create a list of lists for each block name and store the indices in each list for example:

#
(setq BlockIndices (list
("sampleBlockName" 1 25 40)
("otherBlock" 3 5 7)
))

 

And use vla-item to pick items as the BlockList iterates

 

Above would mean the modelSpaceBlocks list will have an equal number (or less) items as the blockList. Which would be follwed with something like:

(vlax-for [color=red][b]blockList[/b][/color] [b][color=blue]c[/color][/b]
    (setq i -1)
    (while (< )setq i(1+ i))(length blockIndices))
      (if(equal (vla-get-name c)(nth i (car blockIndices))
       (progn
        (someFunction(mapcar 
          '(lambda(y)(nth x modelSpaceBlocks )) (cadr modelSpaceBlocks) )
         (setq i (length blockIndices))
     )
   )
 )

 

There would only be one comparison of the names and then mapcer to pick them up

 

 

This just confuses me to no end :? ...

 

Also, watch your syntax:

 

([b]foreach[/b] [b][color=#0000ff]symbol[/color][/b] [color=red][b]List[/b][/color]

 

([b]vlax-for [color=blue]symbol[/color][/b] [color=red][b]collection[/b][/color]

Posted
No worries, you were explicit about providing an example based on the OP's code.

 

This just confuses me to no end :? ...

 

Also, watch your syntax:

 

([b]foreach[/b] [b][color=#0000ff]symbol[/color][/b] [color=red][b]List[/b][/color]

([b]vlax-for [color=blue]symbol[/color][/b] [color=red][b]collection[/b][/color]

 

Lol thanks; I'm writing the code in the quick post didn't even notice I had it back to front:lol:

 

The code you've quoted covers all the comparisons in one iteration through modelSpaceBlocks and then uses the indices to in the subsequent mapcar to collect all the blocks associated with the current blockList item's name. The method that would need to be used to create blockIndices would be a bit messy or at least not suited to mapcar if using sset to get the blocks. This would however have the fewest vlax*,vla*, vl* calls - I think

 

EDUT:

 

In hindsight this post may not explain the blockIndices list creation very well. I'm working at the moment but will try to post a suitable method when I finish.

Posted

Well after pondering on how to write the function to create the function it dawned on me that we've deviated from the topic in such a way that my approach to indexing would benefit from vl-sort for quickness of collecting blocks (sort by object type and name) which would then make the second part redundant as you'd be as well just using the vl-sort and creating the a list containing a list containing a list of block references grouped by name with only one iteration through the blocks.

 

Perhaps the opening example wasn't the best for the discussion - if nothing else I've learned a lot

Posted (edited)

I'm a bit late to the party, but, after glancing through the posts in this thread it appears things are being overcomplicated.

 

Here's the way I see things:

 

If you need to operate on the block definitions for all blocks in Modelspace, then Renderman's code from here is the route I would be inclined to follow, since you only need to process one Block Reference for each Block Definition.

 

If you are performing an operation to affect each Block Reference (for example changing the properties per Reference, or accessing the attributes for an attributed block), then a list needn't be created and you would just iterate through all block references in an acquired SelectionSet.

 

Looking over your code, SOliver, I notice you using indexes to iterate through lists. Whilst in languages such as C/C++ where arrays are used within for loops, this is the usual practice:

 

#include <iostream>
using namespace std;

int main ( )
{
 int myArray[5] = {1,2,3,4,5};
 int total = 0;

 for(int i=0; i<5; i++)
   total += myArray[i];

 cout << "Total is: " << total << endl;
 return 0;
}

(Excuse my simple example)

 

LISP makes things easy by supplying the developer with tools such as foreach/vlax-for loops, hence removing the need to create and iterate using an index.

 

Same example in LISP:

(defun test ( / myArray total )

 (setq myArray '(1 2 3 4 5))
 (setq total 0)

 (foreach x myArray
   (setq total (+ total x))
 )
 (princ (strcat "\nTotal: " (itoa total)))
 (princ)
)

Hope this offers something helpful.

 

Lee

Edited by Lee Mac
Posted
I'm a bit late to the party, but, after glancing through the posts in this thread it appears things are being overcomplicated.

Spoken by the man posting C in a LISP forum. :roll:

Posted

...

If you need to operate on the block definitions for all blocks in Modelspace, then Renderman's code from here is the route I would be inclined to follow, since you only need to processed one Block Reference for each Block Definition.

...

 

Thanks, Lee! :)

Posted
What. ever.

 

It was posted to demonstrate a point - what's the problem?

Posted
It was posted to demonstrate a point - what's the problem?

 

(quote chosen solely due to it's position in the sub topic)

 

Not one to be pedantic but the code posted would be c && c++ Compatible :shock:

 

I've never been a fan of the "foreach" function, again probaly down to too much php [sic] I wrote several function in lisp to mimic php's array handling. Lisp doesn't have a "return" function which is one of the reason why I use iterators as a method of cutting an action short if required. That said vlax-for has a small place in my heart for odbx-based scripts.

 

To be honest the thread went on a tangent from the offset and the comments made by RenderMan and Alanjt sent me off on a wild lisp fuelled by curiosity and an obsession for efficiency :D

 

The thread was originally opened to discuss the point in which vl-remove becomes useful - granted to my discredit the example was at best misleading.

 

Final note: This thread gave me a slight sense of shame. The production code mentioned in the first post, while not completely conforming to the example; could have been drastically improved if I had started this thread earlier. Still he who makes mistakes and notes them staggers closer to enlightenment.

 

SOliver.

Posted
Not one to be pedantic but the code posted would be c && c++ Compatible :shock:

 

I didn't think the include statements would be compatible, nor that C had a 'cout' expression, only printf?

Posted
I didn't think the include statements would be compatible, nor that C had a 'cout' expression, only printf?

 

Lol you've got me there Lee; the post was ill-informed trolling. I haven't touched either languages in years.

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...