For Loop

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 of exit for performance reasons. The while expression is evaluated before the where 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