CDL Iterator Statements and the COLLECT Operator
The COLLECT operator supports iterator statements.
This section includes the following:
-
Syntax for the operator COLLECT
-
How an iterator can use the COLLECT operator to specify the domain of the collection that's passed to an aggregation function.
-
Using the DISTINCT keyword to collect distinct values from an attribute
COLLECT Operator
Aggregation functions such as Min(...), Max(...),
Sum(...), and AnyTrue(...) accept a collection of values as an operand.
An iterator can use the COLLECT operator to specify the domain of
the collection that's passed to the aggregation function. In many
cases FOR ALL serves that purpose. The following example shows
a single contribution of the maximum value of the collection of children
of option feature a
using a COLLECT
operator and a FOR ALL iterator.
COLLECT Operator, Single Contribution
ADD Max({COLLECT &var FOR ALL &var IN {OptionsOf(a)}}) TO d;
The previous example has the same result as the following example:
ADD Max &var TO d
FOR ALL &var IN {OptionsOf(a)} ;
The COLLECT operator is necessary when limiting an aggregate. The following example shows a rule where the iteration of the FOR ALL and WHERE clauses result in an error for every element of the collection {Option11, Option32, OptionsOf(Feature1)} that doesn't contain the user-defined attribute UDA1
CONSTRAIN &varA IMPLIES model.optionClass.item
FOR ALL &varA IN {Option11, Option32, OptionsOf(optionFeature1)}
WHERE &varA.userAttrs["UDA1"] = 5;
The following example uses COLLECT, which prevents the error.
COLLECT Operator Contributions
CONSTRAIN &varA IMPLIES model.optionClass.item
FOR ALL &varA IN {Option11, Option32, {COLLECT &varB
FOR ALL &varB IN OptionsOf(optionFeature2)
WHERE &varB.userAttrs["UDA1"] = 5}};
COLLECT can be used in any context that expects a collection. The COLLECT operator can be used along with a complex expression and a WHERE clause for filtering out elements of the source domain of the collection.
Since COLLECT is an operator that returns a collection, it can also be used inside of a collection literal, as long as the collection literal has a valid inferred data type. The Configurator compiler flattens the collection literal during logic generation, which allows collections to be concatenated. See Collection Literals for details.
The COLLECT operator can have only one iterator, because the return type is a collection of singletons. CDL doesn't support using a Cartesian product with the COLLECT operator.
The COLLECT operator can't put dynamic variables in the IN and WHERE clauses, as this may result in a collection that's unknown at compile time.
The COLLECT operator can use the DISTINCT keyword to collect distinct values from a user-defined attribute, as shown in the following example , which prevents the selection of options having different values for the user-defined attribute Shape from the option class optionClass3. optionClass3 has zero Minimum Quantity and no limit on Maximum Quantity.
COLLECT Operator with DISTINCT
AnyTrue({COLLECT &opt1
FOR ALL &opt1 IN {'optionClass3'.Options()}
WHERE &opt1.userAttrs["Physical.Shape"] = &shape})
EXCLUDES
AnyTrue({COLLECT &opt2
FOR ALL &opt2 IN {'optionClass3'.Options()}
WHERE &opt2.userAttrs["Physical.Shape"] <> &shape})
FOR ALL &shape IN
{COLLECT DISTINCT &node.userAttrs["Physical.Shape"]
FOR ALL &node IN 'optionClass3'.Options()}