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()}