Skip to main content

forAll

Loops through a list (or array) and applies a function to all items.

The first parameter defines the input list, and the second defines the function. You can write the function as a lambda expression or give the name of a user-defined function.

forAll is similar to map but returns a concatenated string instead of a list. This makes it ideal for running multiple data objects — e.g. all objects in a JSON array — through a parameterized script.

Parameters

  • INPUT LIST (list or array)

    The input data. A list or JSON array.

  • FUNCTION (function)

    The function to apply to all items within the list/array.

    Write a lambda expression or the name of a user-defined function.

forAll vs. map

The forAll and map functions both apply a function to each item in a list/array. The difference is that forAll returns a concatenated string whereas map returns an amended data list.

ATL in Script

Printed Result

[[
myList = ('John', 'Paul', 'George', 'Ringo');
forAll(myList, x -> upper(x))
]]

JOHNPAULGEORGERINGO

[[
myList = ('John', 'Paul', 'George', 'Ringo');
map(myList, x -> upper(x))
]]

JOHN, PAUL, GEORGE and RINGO

Both examples take a list (myList) and use the lambda x -> upper(x) to apply uppercase formatting to all list items. The map function is better for this purpose as it returns a data list rather than a concatenated string. A much better use case for forAll is shown below.

Note

  • Use map to generate a list of values from your data.

  • Use forAll to run multiple data objects through a parameterized script.

Examples

Assume a "Describe a JSON Object" project with this data:

{
    "offices": [
        {
            "name": "Los Angeles",
            "sales": 85320,
            "target": 75000
        },
        {
            "name": "Houston",
            "sales": 70530,
            "target": 75000
        },
        {
            "name": "New York",
            "sales": 280425,
            "target": 200000
        },
        {
            "name": "Dallas",
            "sales": 45090,
            "target": 50000
        }
    ]
}

The "offices" array contains four JSON objects, one for each office. Suppose you want to generate a narrative that includes a summary of each office. This requires you to write a user-defined function (UDF) that takes an object and returns text. You can then use forAll to apply this UDF to each object in the array.

Important

Download and open THIS EXAMPLE PROJECT to work through the examples.

Using the example project, follow these steps:

  1. Create a new script and name it DescribeOffice.

  2. Copy-paste in this ATL:

    #define DescribeOffice(object)
    
    The [[object.name]] office [[if(object.sales > object.target){performed well}else{did poorly}]], with sales [[abs(percentageChange(object.sales,object.target))]]% [[if(object.sales > object.target){above}else{below}]] target.

    This user-defined function — also known as a parameterized script — takes one parameter (object). The input will be an object from the "offices" array in our data. The forAll function will pass in the object when it loops through the whole array.

    Make sure there is a full carriage return after the first line. The script should look like this:

    forAll1.png
  3. Go to the Main script and add this ATL:

    [[forAll(WholeJSON.offices, DescribeOffice)]]

    The first parameter input (WholeJSON.offices) accesses the "offices" array. The second parameter input is the name of our user-defined function. The forAll function will loop through the input array and apply the DescribeOffice function to each object.

    Tip

    You could achieve the same effect with a lambda expression:

    [[forAll(WholeJSON.offices, object -> DescribeOffice(object))]].

  4. Preview the Main script. You should see this result:

    The Los Angeles office performed well, with sales 13.8% above target.

    The Houston office did poorly, with sales 6.0% below target.

    The New York office performed well, with sales 40.2% above target.

    The Dallas office did poorly, with sales 9.8% below target.

forAll and random variation

Using forAll in the way shown above might produce a strikingly similar output for each object. The effect might be a repetitive narrative that appears machine-generated. You can fix this by combining forAll with chooseAtRandom to add random variation.

Open the example project and follow these steps:

  1. Create a new script and name it DescribeOfficeAlt.

  2. Copy-paste in this ATL:

    #define DescribeOfficeAlt(object)
    
    Total sales in [[object.name]] [[if(object.sales > object.target){exceeded}else{missed}]] the target by [[abs(percentageChange(object.sales,object.target))]]%.

    This script returns the same information as the DescribeOffice script but with slightly different wording.

    IMPORTANT: Make sure there is a full carriage return after the first line.

  3. Go to the Main script and replace the existing content with this ATL:

    [[forAll(WholeJSON.offices, object -> chooseAtRandom(DescribeOffice(object), DescribeOfficeAlt(object)))]]

    The input to the second parameter is a lambda expression. The forAll function still loops through the "offices" array, but now it applies the DescribeOffice or DescribeOfficeAlt function, selected at random.

  4. Click Preview to see the effect. You should see a result like this:

    Total sales in Los Angeles exceeded the target by 13.8%.

    The Houston office did poorly, with sales 6.0% below target.

    The New York office performed well, with sales 40.2% above target.

    Total sales in Dallas missed the target by 9.8%.

    The output now has more variety.

    Tip

    Remember, chooseAtRandom can take any number of parameters. If required, you could write the lambda expression to randomly select from many more options.

forAll and conditional variation

You can embed a conditional statement in your call to the forAll function. For example, suppose that you want to generate a specific narrative for the top-performing office.

Using the example project, follow these steps:

  1. Create a new script and name it DescribeTopOffice.

  2. Copy-paste in this ATL:

    #define DescribeTopOffice(object)
    
    [[object.name]] was the top performer, [[if(object.sales > object.target){surpassing}else{despite missing}]] its sales target by [[abs(percentageChange(object.sales,object.target))]]%.

    IMPORTANT: Make sure there is a full carriage return after the first line.

  3. Go to the Main script and replace the existing content with this ATL:

    [[forAll(WholeJSON.offices, object -> object.name == topOffice ? DescribeTopOffice(object) : chooseAtRandom(DescribeOffice(object), DescribeOfficeAlt(object)))]]  

    The lambda expression uses a conditional statement written in ternary syntax.

    If the object's name value is EQUAL TO the topOffice value, the function uses DescribeTopOffice. Otherwise, the function randomly selects and applies either DescribeOffice or DescribeOfficeAlt.

    Tip

    Note that topOffice is a user-defined variable that returns the name of the top-performing office. To see the ATL for this variable, look at the project's Variables view.

  4. Click Preview to see the effect. You should see a result like this:

    Total sales in Los Angeles exceeded the target by 13.8%.

    The Houston office did poorly, with sales 6.0% below target.

    New York was the top performer, surpassing its sales target by 40.2%.

    Total sales in Dallas missed the target by 9.8%.

    The output now identifies the top-performing branch.