The for
loop iterates through a range of numbers, time values, or a sequenced collection of values such as, an array or object set.
The syntax for the for
loop is:
for <var_name> [, <index_name>[, <filtered_index_name>]] ( in | = )<sequence> ( do | collect ) <expr>
where <var_name>
is the name of the loop item variable that holds the loop value, and <sequence>
is the source of values for the loop.
The <index_name>
and <filtered_index_name>
are optional variables that hold the loop's index. The <index_name>
is unaffected by any filtering expressions (where), and corresponds to the value's position in the original list. The <filtered_index_name>
is the position of the value in the filtered list. See the examples below for an illustration of the difference between these two indices.
Available in 3ds Max 2021 and higher.
The <sequence>
can be one of the following:
<expr> to <expr> [ by <expr> ] [while <expr>] [where <expr> ]
<expr> [while <expr>] [ where<expr> ]
<expr> to <expr> [ by <expr> ] [where <expr> ]
<expr> [where <expr>]
EXAMPLES:
for i = 1 to 10 do print i -- sequence numbers
for item in table1 do x = x + item.height -- sequence an array
for t in 0f to 100f by 5f do sliderTime=t -- sequence time (given as frames, here)
bigones = for obj in $box* -- you can sequence pathnames! where obj.height > 100 collect obj -- collect the big boxes into an array
for i,j,k = 12 to 24 where (mod i 3 == 0) do ( -- filter numbers divisible by 3 format "val:% index:% filtered index:%\n" i j k ) --> produces this output: val:12 index:1 filtered index:1 val:15 index:4 filtered index:2 val:18 index:7 filtered index:3 val:21 index:10 filtered index:4 val:24 index:13 filtered index:5
The first <sequence>
form is the standard number loop, the first <expr>
value is the start value, the to <expr>
value is the limit value and the optional by <expr>
value is the loop value increment. The allowable value types are integer, float, and time. If the by
value is not given, it defaults to 1.
The second form of <sequence>
takes a sequencable collection such as, an array or ObjectSet, and iterates through all its values assigning successive elements in the collection to the loop value each time through the loop. MAXScript contains several sequence collections including PathName values, the current selection set, the children of a node, and the stack of modifiers on an object. See also Collections for caveats when using a collection in a for
loop.
If an optional while <expr>
test is specified, the for
loop terminates if the test evaluates to false
. The while
test expression must evaluate to a boolean ( true
/ false
).
PERFORMANCE WARNING
Breaking out of a loop using an
exit
construct is implemented internally using try/catch, which is extremely slow.This is why the use of the
while
test is recommended over the use ofexit
for performance reasons. Thewhile
expression is evaluated before thewhere
expression.
EXAMPLES:
function findByClass _obj _className = ( local notFound = true local res = 0 local searchName = _className as name for i = 1 to _obj.NumBakeElements() while notFound do ( local myElement = _obj.GetBakeElement i if myElement.enabled do ( local eleName = (classof myElement as string) as name if eleName == searchName do ( res = i notFound = false ) ) ) return res )
Each <sequence>
source form takes an optional where <expr>
that must evaluate to true
or false
. The where
expression is evaluated at the beginning of each loop and only executes the loop body for that loop value if the where
expression is true
.
The do <expr>
form simply evaluates the body expression once for each value in the sequence. The loop variable is visible to the code in the body expression as though it was declared locally and initialized to the successive loop values each time. When the do <expr>
form of a for
loop is used as an expression, its return value is always OK
.
The collect <expr>
form gathers the expression values from the loop iterations and stores them in an array, which is then yielded as the value of the overall for
loop. For example, this is a good way to gather procedural selections of objects from a scene. If the where
expression is used with the collect
form of the for
loop, only the values from those iterations for which the where
expression is true
are collected. This can be used to collect a filtered sub-set of the iterated values. You can also achieve this collection filtering in a for
loop that does not use a where
expression by yielding the special value dontCollect
for those iterations that must not be added to the collection.
As described in Scope of Variables, a for
loop creates a new scope context. The for
loop index variable's scope is always the extent of the for
loop, even if another variable of the same name already exists. Once the for
loop exits, the for
loop index variable is no longer accessible. The scope of any variables created in a for
loop is always the extent of the for
loop. This is shown in the following example:
EXAMPLES:
obj=box() avg_pos=[0,0,0] offset_pos=[100,100,0] -- new for loop index variable obj created even though -- a variable named obj already exists, scope is for loop for obj in $* do ( -- new variable pos created, scope is for -- loop offset_pos already exists outside -- for loop, its value will be used pos=obj.pos-offset_pos -- avg_pos already exists outside for loop, -- its value will be used for loop index since variable -- obj goes out of scope avg_pos += pos ) avg_pos /= $*.count