DEV Community

Cover image for Array indexOf() method made simple for Data Analytics in charts and graphs..featuring Grouping, Summing and Rendering
Rick Delpo
Rick Delpo

Posted on

Array indexOf() method made simple for Data Analytics in charts and graphs..featuring Grouping, Summing and Rendering

Did you know that grouping is still unfinished in the Javascript API specification as of 2023? It's not even officially standardized yet. No wonder why it is so difficult to pull charts off in JS and why third party libraries are widely used. After researching this topic I discovered how much is out there and how confusing it is, to the point where we developers just want to give up. Read on and I will show u an easy way to build a quick bar chart dashboard.

We iterate over arrays in Data Analytics thus creating useful insights which add meaning to our data. Charts and graphs enable this process.

Since arrays are iterative by default I like using the indexOf() method to do my grouping because it shows the raw iterations, ie the status of our object for each iteration. Here I am trying to explain indexOf() in plain English.

IndexOf() returns the index position of an array for each iteration. Index is the location of an element in an array starting at position 0. We first query the array to find an element. var x = array.indexOf(element); On the second pass our index is incremented by 1 and so on.

Iteration begins with line 1 of our array for an object and if our search criteria is not found then the index position becomes -1. We then include our object and while this object is then found in the next iterations we sum values when index position is not -1 (index is zero at this iteration). When the object changes we have -1 again because on first pass the object is not found until we add it, and we start our summing all over again. This behavior is grouping. It is a while loop.

use case - group months for product sales and sum multiple product sales values for each month. Eg. while month is January sum 3 product's sales for records with month as January. Start over again for February.

var original_array =
[{"order_date":"01-03-22","product_line":"prod1","dollar_amt":100,"product1":200,"product2":0,"product3":0},
{"order_date":"01-02-22","product_line":"prod2","dollar_amt":50,"product1":0,"product2":50,"product3":0},
{"order_date":"1-16-22","product_line":"prod3","dollar_amt":50,"product1":0,"product2":200,"product3":50},
{"order_date":"1-17-22","product_line":"prod1","dollar_amt":100,"product1":100,"product2":0,"product3":0},
{"order_date":"1-15-22","product_line":"prod2","dollar_amt":50,"product1":0,"product2":50,"product3":0},
{"order_date":"2-5-22","product_line":"prod1","dollar_amt":100,"product1":100,"product2":0,"product3":0},
{"order_date":"2-6-22","product_line":"prod3","dollar_amt":20,"product1":0,"product2":30,"product3":20},
{"order_date":"2-7-22","product_line":"prod1","dollar_amt":100,"product1":100,"product2":0,"product3":0},
{"order_date":"3-23-22","product_line":"prod2","dollar_amt":200,"product1":0,"product2":200,"product3":0},
{"order_date":"3-5-22","product_line":"prod3","dollar_amt":20,"product1":0,"product2":100,"product3":20},
{"order_date":"3-29-22","product_line":"prod1","dollar_amt":100,"product1":100,"product2":0,"product3":0},
{"order_date":"3-25-22","product_line":"prod1","dollar_amt":100,"product1":100,"product2":0,"product3":0},
{"order_date":"4-23-22","product_line":"prod1","dollar_amt":500,"product1":500,"product2":50,"product3":50},
{"order_date":"4-24-22","product_line":"prod2","dollar_amt":100,"product1":0,"product2":100,"product3":50},
{"order_date":"5-10-22","product_line":"prod3","dollar_amt":50,"product1":0,"product2":0,"product3":50},
{"order_date":"5-15-22","product_line":"prod1","dollar_amt":500,"product1":100,"product2":0,"product3":0},
{"order_date":"5-25-22","product_line":"prod2","dollar_amt":50,"product1":0,"product2":50,"product3":150}]

; //end of array

       //first transform original array into product sums for each month array, then used to populate bar chart

  // Because JS doesn't have a nice way to name months
var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var result = [];   //transformed array after below operations are performed
var dateArr = [];   //starts empty, to keep track of month names
let initialValue = 0; //need to pass in an initial value or reduce omits first element of array

var dataByMonth= original_array.reduce(function(prev, currValue){ 
date = new Date(currValue['order_date']); //for js date to work must be inside a function, needs valid data format yyyy etc
      //next 3 lines converts non conforming date on the fly so conforming/valid date can be used in date object
var dateString = new Date(date.getTime() - (date.getTimezoneOffset() * 60000 ))
                    .toISOString()
                    .split("T")[0];
console.log(dateString);

  date = monthNames[date.getMonth()]; //gets month names to be grouped below     //we are iterating over month names array at each pass     //if cur mo is not found in dateArr then start summing //keep summing while cur mo is found in each subsequent pass
console.log("date.getMonth()= "+date);
               //next, indexOf is acting like a find function
   var index = dateArr.indexOf(date); //equaling -1 on first pass of ea mo until that mo is added to the array  //because there is no match for date in dateArr on first occurrance of mo
//first check to see if dateArr has mo name, on new mo will not have so index is -1
        console.log("index = "+index);

   if (index == -1) {  //is equal to -1 only for first pass, above forces -1 so we can initialize first pass
       dateArr.push(date);  //no match for month name until it is pushed..dateArr starts as empty until mo val is pushed
          var obj = {month: date, product1: currValue.product1, product2: currValue.product2, product3: currValue.product3};
      result.push(obj); //push in default vals for new mo
   } 
   else {
//index = 0 because dateArr has val now...then for next mo index=1
               //on subsequent passes index will not be -1 so just increment cur vals until new mo is encountered
           result[index].product1 += currValue.product1; //increment sum each pass starting index =0
           result[index].product2 += currValue.product2;   //no need to push, result val updates each time
           result[index].product3 += currValue.product3;
   }
console.log("dateArr "+dateArr);
return prev +currValue; //need to return both prev and curr, for first element to register
} //end of reduce

, initialValue);  //initial value here, this is the 2nd arg of array.reduce, first arg is callback function above

console.log(JSON.stringify(result, null, 1));

Enter fullscreen mode Exit fullscreen mode

ps: there are other ways to group data such as array.groupBy() or lodash but 1 is confusing and 2 adds a library which I am trying to avoid.

note: above code is only a segment of the total solution to be found here: (make this stacked bar chart your next JS project)
https://dev.to/rickdelpo1/how-to-populate-a-stacked-bar-chart-in-plain-javascript-12p9

problem statement:
Grouping is critical in data analytics when we are using charts yet a Javascript standard is not in place yet forcing us to cobble together whatever we can and often just giving up.

Most charts have a time series on the x axis and for marketing and sales data it is usually a by month time line in our graph. It is 2023 and Javascript Ecma International is still trying to get this right. It is no wonder why many third party libraries popped up like underscore, lodash and moment. But these libs add complexity when we can solve the issue using only a few lines of native js code. Also external libraries slow down our web page load time.

Easy to understand solution:
The advantage of using indexOf() is that it demonstrates the iterative process on an array which is, bottom line, the whole essence of data structure Array. In my opinion it is the least confusing way to group data and leads us to an easy solution and a finished project.

caveat..Many examples out there show a grouping method but do not combine it with summing which is a must have in data analytics when building charts. We want the sum of products for each month not just the records grouped by month. These are 2 different things. It is a bit insidious at first where grouping alone does not solve the problem.

Thanks for reading folks and don't forget to click above for my stacked bar chart using this easy grouping logic. Once on my project page u can click my codepen for the full code.

Top comments (0)