For Loop Collect Vs For Loop Do Performance

MAXScript FAQ > How To Make It Faster > For Loop Collect Vs For Loop Do

A user asked:

I was quickly making a script to select all objects and I realized that it was very slow, even with undo off, disableSceneRedraw and suspendEditing.

for o in objects do selectmore o

I thought a bit and discovered that I could select an array of objects like in this code:

a=#()
for o in objects do append a o
selectmore a

The difference in speed is really huge (like 3000%+ faster).

But there is absolutely no reference to the possibility of selecting an array of objects in the MAXScript help, even in the "how to make it faster" section.

Is there anything I should know about that way of selecting objects?

Why isn't that documented a tall as it looks very effective?

Answer:

The truth is people tend to code differently.

All the info needed was in the Reference, but it did not really tell you "Don't do this" because nobody can anticipate every possible expression someone might write.

Doing things one at a time instead of once for the whole collection sounds like it would be slow, and it is.

The first example loops through an ObjectSet and sets the isSelected property of the node to true for each one, which is very very slow.

The second example does indeed call selectMore() in a mapped fashion, but the array building is a bit inefficient, as it uses append() which has to grow the array on each call by duplicating the previous array in memory. With few objects it would be negligible though, with a lot more objects it might start causing slowdowns...

POSSIBLE EXPRESSIONS

If you really have to do a FOR loop, use the COLLECT form instead of DO. It builds the array and gives back the result without using append() explicitly or any intermediate variables to store the array. You could assign to a vatiable if you want to keep the selection snapshot around.

It would be something like:

select (for o in objects collect o)

This would allow you to apply where conditions, for example to select all visible objects,

select (for o in objects where not o.isHiddenInVpt collect o)

or, if this really is what you are trying to do, selecting ALL scene object, simply

select objects

There is no reason to do selectmore() if you are selecting all scene objects anyway, and you can operate on the live collection of scene objects without converting it to array. Note that select() will make sure the previous selection is removed, while selectMore() will obviously add to the existing one.

SOME BENCHMARK RESULTS

The time is measured on the same reference computer around the select() method and does NOT include the time it takes the viewport(s) to actually redraw, just the time to set the selected flags of the nodes.

EXPRESSION 1 - SELECT ALL

select objects

With 100objects (boxinstances), the above expressiontook31 ms.

With 1,000objects, it took 78ms.

With 10,000objects, it took 328ms.

With 100,000objects, it took 15,468ms.

EXPRESSION 2 - DO, APPEND AND SELECT

a=#()
for o in objects do append a o
select a

With 100, 1000 and 10,000 objects, the above expression performed similarly to the first one, proving that the memory overhead of the array management is not measurable with relatively low numbers of iterations.

The code is longer and less elegant though.

With 100,000 objects, the expression took 17,547ms., or about two seconds more than the first expression.

EXPRESSION 3 - TEST, COLLECT AND SELECT

select (for o in objects where not o.isHiddenInVpt collect o)

The above expression took around 430ms with 1000 objects.

Performing a condition test on 1000 objects does not make a significant difference, but increases the flexibility of the expression to select specific objects by their properties.

EXPRESSION 4 - DO AND SELECT MORE

for o in objects do selectMore o

The above expression took only 171 ms if all 1000 objects were already selected because it had nothing to do, but 674172 ms (over 11 minutes!!!) if none of the 1000 objects were selected!

STAY AWAY FROM IT!

Previous Tip

For Loop By Index Vs For Loop Through Collection Performance

Next Tip

Optimizing Particle Flow Script Operator For Loops For Speed