Skip to Content
Technical Articles
Author's profile photo Robert Schmidt

For Loops in Analytic Designer

There are two types of For loops in most scripting language today. I refer to these loops as Old School and New School loops. Old school loops determine the number of elements to loop through and new school loops implicitly loop through the elements. In this blog, I want to explore both types of loops.

For this discussion, I am going to create to charts on the Analytic Designer canvas using SAP’s Beast Run Company data. The first chart has a know number of dimension values, for which I am using the Advanced Purchase Group dimension. The other chart has a variable number of dimension values, for which I am using the Traveler ID dimension. I named these charts chrtAdvanced and chrtTraveler.

I am also going to add a button to the canvas

Name: btnOldSchool
Text: Old School Loop

Old School For Loops

We will start the code for old school with these two with these two lines of code:

var arrAdvance = chrtAdvanced.getDataSource().getMembers("Advance_Purchase_Group");
var arrTraveler = chrtTraveler.getDataSource().getMembers("Traveler_ID", 10);

These lines of code will return the data members to their respected variables – arrAdvance & arrTraveler. Both of these variables are arrays of member data. We may know that the arrAdvnce array contains 5 elements, because their are only 5 Advance Purchase Groups. However, we probably do not know how many traveler ids there are, so we can not know how many elements are in the arrTraveler array.

Lets do the advance purchase group loop first. To do this we are going to put the following lines of code after are previous two lines:

Code:
for (var i=0; i<5; i++){

console.log(arrAdvance[i]);
}

Output:

In this code we declared and used the variable i in the For loop definition. Javascript arrays start at zero, so we set the initial value of i to zero. We wanted to loop 5 times, so we looped while i was less than 5. If we would of looped to i less than or equal to 5, then we would of looped 6 times. The i++ simply states to increment by 1. I call this old school, because this how for loops have been coded since fortran and pascal days.

The code inside the loop parentheses displays the content of the arrAdvance element in the Google console. To see the console in Google, press the F12 key after running the Analytic Application.

After observing the output, we should realize that not all advance purchase groups are displayed. We are missing the >20 group. This happened, because we got one group that we were not expecting, which is the unassigned group. Even though this group is not displayed in the chart, it must be in the data set that supplies data to the chart.

To rectify this, we could simply increase the for loop iterations by 1, as in

Code:
for (var i=0; i<=5; i++){
console.log(arrAdvance[i]);
}

Output:

Now, we have the >20 group. If the programmer was absolutely certain that there will never be another group defined, then this code would be all right. Not the best, because it is not able to adjust to advance purchase group redefinitions.

To make this code better, we could replace the integer limit of 5 with a piece of code that will tell us how many elements are in the array. Then the code will look like this:

Code:
for (var i=0; i < arrAdvance.length; i++){
console.log(arrAdvance[i]);
}

Output:

In this code we are using the length property to return the number of elements in the array. We also switched back to less than, because the arrays are zero based and the length includes the zero element.

This would be the same code that we would use for the arrTraveler array, because the number of travelers is variable. In our example, we limited the number to 10, but if the timespan was small enough, then we could get less than 10 travelers.

Code:

// Get Dimension members for both data sources
var arrAdvance = chrtAdvanced.getDataSource().getMembers("Advance_Purchase_Group");
var arrTraveler = chrtTraveler.getDataSource().getMembers("Traveler_ID", 10);

//Output Dimension Members
for (var i=0; i<arrAdvance.length; i++){
   console.log(arrAdvance[i]);
}

for (i=0; i<arrTraveler.length; i++){
   console.log(arrTraveler[i]);
}

Note: Notice the second loop definition for (i=0; i<arrTraveler.length; i++) does not have var i, like the first. The var statement is not needed, since it is used to declare a new variable, and i has already been declared in the first loop.

Output:

I call this old school for loops, because we determine the number of iterations needed, and then define the for loop for that number of iterations. I usually write my loops in this manner, but I am still stuck in the past.

New School For Loops

New school loops don’t use predetermined limits, and will loop through the elements of an object. In some languages arrays are objects and new school loops can be used with arrays. However, in SAP Analytic Designer these types of loops cannot be used with arrays. So in our example, we will loop through the elements of a selection array with old school looping, and then loop through the Selection object with new school looping. Below in the code that we will use.

Code:

// Get Dimension members for both data sources
var selAdvance = chrtAdvanced.getSelections();

//Output Dimension Members
for (var i=0; i<selAdvance.length; i++){
 for(var dimensionId in selAdvance[i]){
      console.log(dimensionId + ‘: ‘ + selAdvance[i][dimensionId]);
   }
}

Note: We place this code in the onSelect for chrtAdvanced.

Output:

This code is placed in the onSelect for chrtAdvanced, because we want to examine the selections as they are being selected. When an element in a chart is selected, a selection objected is populated. This object will contain the dimensions and their identifiers, and also the identifiers for the measures. If you are unfamiliar with the Selection object, then please read my blog titled: Retrieving Selections from a Chart (Analytics Designer).

In the output above, we see that the selection object has two properties – Advance_Purchase_Group & @MeasureDimension. I f I add another dimension: Cabin Class and another measure: Mileage to the chrtAdvance chart, then the output would look like the following for one selection:

It is a little strange looking, because the dimensionId’s seem to repeat, but all six of these values seem to be stored for one selection if there are multiple measure and dimension values.

Note: The dimensionId’s repeat, because there are two measures,and I selected a dimension value. With a selected dimension, then there are two measure objects: Count and Mileage. If I selected a measure value by clicking on a number in the chart, then the output would have simply been the two dimension Advance_Purchase_Group and Cabin_Class, and the single measure id:

The code,

for(var dimensionId in selAdvance[i]){
console.log(dimensionId + ‘: ‘ + selAdvance[i][dimensionId]);
}

loops though the object properties of selAdvance[i]. We do not know how many properies there are, we will simply loop through all of the properties. In the console.log statement, we are outpping the value of dimensionId and we discover that it is not even an integer, which is what we would use to loop through an array. This is why we cannot use the New School looping on an array, as we would need integer offsets into the array.

However, we use the dimensionId in an object, as we would use an integer in an array:

selAdvance[i][dimensionId]

The un-bold part is array reference and the bold part is object reference.

Conclusion

I hope that this discussion will help you to better understand for loops in Analytic Designer. I have not yet use For Each loops in Analytics Designer, but I don’t think that this loop is available. If you have any comments or questions, then please leave them and I will respond.

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Krzysztof Grzymala
      Krzysztof Grzymala

      Hello Robert,

      Thank you for your effort - Great blog!

      I wonder what your view is on the use of 'Cross Calculations' within scripting.

      Let say we wanted to copy filters from one table widget into another (with the use of 'for loop' as it is the subject of this topic!). That is possible now for any dimension within a table but for cross calculation it doesn't work. Let say we got:

      var fleet_out_array = ArrayUtils.create(Type.string);
      var fleet_in_array =Table_1.getDataSource().getDataSelections();
      
      for (var i=0;i<fleet_in_array.length;i++){
       fleet_out_array.push(fleet_in_array[i].BUS_FLEET);
      }
      
      Table_3.getDataSource().setDimensionFilter("BUS_FLEET",fleet_out_array);

      Similar scenario for Cross calculations won't work.

      Do you see any workaround to dynamically drive the cross calculation selection?

      We have already raised some enhancement requests around that:

      https://influence.sap.com/sap/ino/#/idea/243966

      https://influence.sap.com/sap/ino/#/idea/239100

      Regards,

      Krzysztof Grzymala

       

      Author's profile photo Robert Schmidt
      Robert Schmidt
      Blog Post Author

      Hi,

       

      Cross calculations are built on tables, and therefore not available in the data source. What if you moved the calculation into the data source?