Determine the quantity within the data array using javascript

My dataset contains an array with thousands of objects structured like this:

var data = [
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'C',time:'2009'}, 

  {type:'A',time:'2014'},
  {type:'A',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'C',time:'2014'},
  {type:'C',time:'2014'}
];
var validTime = ['2009', '2014'];
var typeArr = ['A','B','C'];

To simplify and consolidate the data, I aim to transform the 'data' array into a new structure called 'newData'. This new structure should calculate the count of each type for every year.

var newData = [
  {time:'2009', A:4, B:3, C:1},
  {time:'2014', A:2, B:3, C:2}
]

I have made some progress in my implementation, but feel that I might not be following the best approach. Being relatively new to JavaScript, I'm seeking guidance on how to proceed or any useful web resources that tackle similar problems. Any assistance would be greatly appreciated! Thanks!

If possible, please include comments in your response.

var arr1 = [];
for (i = 0; i < validTime.length; i++) {
    for (s = 0; s < typeArr.length; s++) {
            var count = 0;
            for (j = 0; j < data.length; j++) {
                if (data[j]['time'] == validTime[i] && data[j]['type'] == typeArr[s]){
                            count++;                                                        
                        }
                    }
                            arr1.push({
                            'type': typeArr[s],
                            'x': validTime[i],
                            'y': count                                              
                            });
                }
            };
console.log(arr1);

Answer №1

Here is a solution that can be used:

let information = [
  { category:'X', year: '2009' },
  { category:'X', year: '2009' },
  { category:'X', year: '2009' },
  { category:'X', year: '2009' },
  { category:'Y', year: '2009' },
  { category:'Y', year: '2009' },
  { category:'Y', year: '2009' },
  { category:'Z', year: '2009' },

  { category:'X', year: '2014' },
  { category:'X', year: '2014' },
  { category:'Y', year: '2014' },
  { category:'Y', year: '2014' },
  { category:'Y', year: '2014' },
  { category:'Y', year: '2014' },
  { category:'Z', year: '2014' },
  { category:'Z', year: '2014' }
];

let newInformation = { };
information.forEach(function(item) {
  
  // Check if the record for this year already exists, if not then create one
  if (!newInformation[item.year]) {
    newInformation[item.year] = { };
  }
  
  // Increment the count of the category for the given year      
  newInformation[item.year][item.category] = (newInformation[item.year][item.category] || 0) + 1;
});

document.writeln('<pre>' + JSON.stringify(newInformation, null, 4) + '</pre>');

 

Answer №2

Check out this library for all your querying needs: https://linqjs.codeplex.com/

Answer №3

let sampleData = [
  {category:'A',year:'2009'},
  {category:'A',year:'2009'},
  {category:'A',year:'2009'},
  {category:'A',year:'2009'},
  {category:'B',year:'2009'},
  {category:'B',year:'2009'},
  {category:'B',year:'2009'},
  {category:'C',year:'2009'}, 

  {category:'A',year:'2014'},
  {category:'A',year:'2014'},
  {category:'B',year:'2014'},
  {category:'B',year:'2014'},
  {category:'B',year:'2014'},
  {category:'B',year:'2014'},
  {category:'C',year:'2014'},
  {category:'C',year:'2014'}
];

let validYears = ['2009', '2014'];
let categoryArr = ['A','B','C'];

// store the result in an object
let results = sampleData.reduce(function (hash, item) {
    if (validYears.indexOf(item.year) >= 0) {
        hash[item.year] = hash[item.year] || {};
        if (categoryArr.indexOf(item.category) >= 0) {
            hash[item.year][item.category] = hash[item.year][item.category] || 0;
        }
        hash[item.year][item.category] += 1;
    }
    return hash;
}, {});

// convert result to array
let value, category, year, resultList = [], dataItem;
for (year in results) {
    value = results[year];
    dataItem = {
        year: year
    };
    for (category in value) {
       dataItem[category] = value[category];
    }
    resultList.push(dataItem);
}

console.log(resultList); // this is the expected output (array)

Answer №4

If you're looking for a simple approach that can be further optimized (especially if the type order is known in advance, like in your example), here's one way to do it:

var updatedData = [];

for (var t = 0; t < validTime.length; t++) {
  var tallyA = 0, tallyB = 0, tallyC = 0;
  for (var i = 0; i < data.length; i++) {
    if (data[i].time === validTime[t]) {
      switch (data[i].type) {
        case 'A':
          tallyA++;
          break;
        case 'B':
          tallyB++;
          break;
        case 'C':
          tallyC++;
          break;
      }
    }
  }
  updatedData.push({time: validTime[t], A: tallyA, B: tallyB, C: tallyC});
}

jsfiddle

Answer №5

Arranging the desired data into arrays can be achieved efficiently by using two small loops instead of your current method.

var data = [

{type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'C',time:'2009'}, 

  {type:'A',time:'2014'},
  {type:'A',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'C',time:'2014'},
  {type:'C',time:'2014'}
];
var validTime = ['2009', '2014'];
var typeArr = ['A','B','C'];
var tempData = {}, newData = [];
var item;

for(var i = 0, len = data.length; i < len; i++) {
    item = data[i];
  if(!tempData[item.time]) {
    tempData[item.time] = {};
  }

  tempData[item.time][item.type] = (tempData[item.time][item.type] || 0) + 1;
}

$.each(tempData, function(index, item) {
  newData.push($.extend(item, {time: index}));
});

console.log(newData);

Check out the code on JS Fiddle here

Answer №6

Consider trying out the use of for loops and for..in loops. The resulting object res will have properties with names corresponding to object type; each property will contain two arrays. The first array should consist of filtered results based on the type, while the second array should include the properties of time for each filtered result, specifically 2009 and 2014.

var data = [
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'A',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'B',time:'2009'},
  {type:'C',time:'2009'}, 
  {type:'A',time:'2014'},
  {type:'A',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'B',time:'2014'},
  {type:'C',time:'2014'},
  {type:'C',time:'2014'}
];

for (var i = 0, res = {}; i < data.length; i++) {
  if (res[data[i].type] === undefined) {
    if (!Array.isArray(res[data[i].type])) {
      res[data[i].type] = [];
      res[data[i].type].push(data[i])
    } else {
      res[data[i].type].push(data[i])
    }
  } else {
    res[data[i].type].push(data[i])
  }
}

for (var prop in res) {
  res[prop] = [res[prop], {2009:[], 2014:[]}];
  res[prop].forEach(function(value) {
    for (var p in res[prop][1]) {
      res[prop][1][p] = res[prop][0].filter(function(v) {
        return v["time"] === p
      })
    }
  })
}

document.querySelector("pre").textContent = JSON.stringify(res, null, 2)
<pre>

</pre>

Answer №7

After some persistence, I managed to find a solution that works perfectly. It was a rewarding challenge for me.

Your current code is generating an array of 6 objects.

{"type":"A","x":"2009","y":4}
{"type":"B","x":"2009","y":3}
{"type":"C","x":"2009","y":1}
{"type":"A","x":"2014","y":2}
{"type":"B","x":"2014","y":4}
{"type":"C","x":"2014","y":2}

accessible from https://jsfiddle.net/aa15y7n0/

The expected outcome is an array with one object per string in the validTime array. These objects should have labels matching those found in typeArr.

To achieve this, I crafted the result array as follows:

var arr2 = [];
// Begin by creating the array with the correct number of objects (2)
for(var i = 0; i < validTime.length; i++) {
    arr2.push({
  'time': validTime[i]
  });
}
// Add the typeArr objects onto these two core objects
for(var i=0;i<arr2.length;i++){
    for(var j=0;j<typeArr.length;j++){
    var thisObj = arr2[i];
    var thisProp = typeArr[j];
    thisObj[thisProp] = 0;
  }
}
// Update values to increment the counters
for(var i=0;i<data.length;i++){
  for(var j=0;j<arr2.length;j++){
    if(data[i].time == arr2[j].time){
        // Increment count of arr2[j].type by 1
      var thisDataObjType = data[i].type;
      arr2[j][thisDataObjType] += 1;
    }
  }
}

You can view the results at https://jsfiddle.net/aa15y7n0/1/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to store AJAX response data for future use

I am struggling with implementing the getState function. My goal is to update a field on click using a state value retrieved from an AJAX call. I have come across mentions of promises in other responses, but I am unsure how to integrate them into my code ...

What is the method for incorporating PHP's header() function within PayPal JavaScript code?

I'm currently working on integrating Paypal with my website and I've run into some issues handling the various messages sent by Paypal, such as success, failed, and cancelled transactions. Below is a snippet of the Paypal JS code where it manage ...

jQuery - Enlarge Tree View to the level of the selected node

I am struggling to figure out how to expand the tree view up to a selected node level. If anyone has any ideas on how to accomplish this, please let me know. For instance, if we click on 'Parent d' in the 'Category list', I want to exp ...

Disregard validation of the view if the element includes the attributes `display: none`

Displayed below is an HTML text input that is designed to toggle visibility using jQuery's slideUp and slideDown functions, which change the display attribute to none with animation. My current challenge is that I do not want to validate the element w ...

Ways to prevent a div from loading an HTML page

When an external button is clicked, the remove() function on id main is triggered. The issue arises when a user quickly clicks on btn1 and then presses the external button, causing the removal to occur before the event handler for btn1. This results in the ...

Steps for displaying an image link on an aspx webpage

Is it possible to have the full-size image open on http//example.com/image.aspx when the thumbnail is clicked, instead of http//example.com/images/image.jpeg? I am looking for a solution that does not require creating individual pages for each image or edi ...

Having trouble retrieving the component state within AgGrid's cellRenderer

When working on my React app using functional components, I encountered an issue with accessing a local state (myObj) within a cellRenderer in AgGrid. The local state is populated via a context object from the parent component based on an API response. Un ...

Guide to Updating Store State with API Data

My goal is to update my component state with data retrieved from an API using a getter in the store. Within the mounted() lifecycle hook, I call the getProducts() getter which is defined as: export const getters = { async getProducts() { axios.ge ...

verifying the presence of a string or value within an array

I'm currently working on a feature that involves adding an element to an array by typing something into a text field and clicking a button. I've also implemented an if statement to check if the input already exists in the table, and show an alert ...

Is it advisable to employ jQuery(this) in this specific scenario?

My PHP script generates HTML a:link divs with different $linkname and $pageid values. It also creates corresponding jQuery scripts for each link: $output = '<a class="sig_lightbox_link" id="' . $pageid . '">' . ...

Arranging and Filtering an Object Array Based on their Attributes

Here is an example of a JSON array called items: var items = [ { Id: "c1", config:{ url:"/c1", content: "c1 content", parentId: "p1", parentUrl: "/p1", parentContent: "p1 content", } }, { Id: "c2", ...

Utilizing inputRef in conjunction with MUI's useAutocomplete

Is there a way to pass the "inputRef" to Material UI's useAutocomplete? I'm looking to set a custom reference on the input, but the getInputProps() method from useAutocomplete already requires its own reference. I've attempted various appr ...

Create a data attribute object and assign to it the prop object received from the parent component

I am struggling with passing an object as a prop from a parent component and then utilizing it to initialize the child component with the received value. The main objective behind this is to create a dialog box that includes a child form component with mu ...

Add a CSS class to an innerHTML element just a single time

I currently have 2 files available: data.php page.php The data.php file is responsible for fetching a row from a SQL database and sending it to the page.php file. Within the page.php file, there is a JavaScript script that receives this row through AJAX ...

The class 'ConsoleTVsChartsCharts' could not be located

Attempting to implement Laravel charts using the package consoletvs/charts:6.*, Utilizing service providers ConsoleTVs\Charts\ChartsServiceProvider::class, With an alias: 'Charts' => ConsoleTVs\Charts\Charts::class, ...

The issue of C# deserialization consistently yielding null values for array elements

I'm encountering an issue with deserializing partially working. When dealing with XML nodes that have attributes, the attribute values are loading correctly into my class. However, when using elements, it results in null values. Here is the content s ...

Combine several dictionary values under a single dictionary key in JavaScript

I have a unique dictionary structure displayed below. My goal is to populate it with values in a specific way. It all begins here var animals = { flying : {}, underground : {}, aquatic : {}, desert : {} }; To illustrat ...

Utilizing jQuery's AJAX method for Access-Control-Allow-Origin

Here's the code snippet I'm working with: $.ajax({ url: url, headers: { 'Access-Control-Allow-Origin': '*' }, crossDomain: true, success: function () { alert('it works') }, erro ...

Save information in a nested object within local storage by utilizing a dynamic key

Storing the below object in localStorage to simulate server-side login/logout functionalities. Current user logic is implemented to identify the logged-in user. let defaultUsers = [ { email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

Tips for formatting a phone number using regular expressions in [Vue 2]

I am currently working on creating regex code that will meet the following requirements: Only allow the first character (0th index) in a string to be either a '+' symbol or a number (0-9). No non-numerical values (0-9) should be allowed anywhere ...