Merge arrays in map function based on label and aggregate information

In my possession is an array filled with data from various streaming channels, categorized by shift (Morning and Afternoon).

I dedicated the night to experimenting with different functions like reduce, but unfortunately, I hit a wall and couldn't grasp its functionality.

var array = [{"label":"morning","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"None":"0.00"},{"Netflix":"55.00"},{"Other":"20.00"}]}...]

The desired outcome:

To calculate the total sum of all streaming channels, divided based on the number of objects per shift (morning and afternoon).

[{"label":"morning","data":[{"Amazon Prime":"16.66"},{"AppleTV":"0.00"},{"HBO Max":"16.66"},{"None":"16.66"},{"Netflix":"43.33"},{"Other":"6.66"}]}...]

Any assistance or explanation would be greatly appreciated!

Answer №1

Let's break down this problem into manageable steps. Initially, we can use the reduce method to iterate over the data and construct an object. The objective here is to create an object where each key represents a label for easy merging of similar keys. Upon reviewing the task at hand, we note that:

  • The numerical values are in string format, making arithmetic operations challenging.
  • Merging subarrays is complex and could benefit from conversion to objects as well.

let array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0...

// The code for initial attempt goes here

%

For the second step, our approach involves:

  • Converting more arrays to objects
    • Object methods such as in can be utilized once we have objects
  • Using parseFloat to convert strings to numbers
  • Collating information to generate raw data effectively.

let array = [{"label"...

// The code for the second attempt goes here

%

Finally, in the last phase, we average out the remaining data arrays and transform the numeric outcomes back into string format.

let array = [{"label"...

// The final code snippet for averaging data

%

A few concluding points regarding this solution compared to the original question provided.

  • I applied toFixed(2) for rounding up:
    • This results in "16.67" instead of "16.66" for the "manha" averages
  • For "tarde", I obtained "37.50" (i.e., (50 + 25) / 2 === 37.50) instead of "36.00"
  • All other output values align with the requirements specified in the question

Answer №2

This code snippet may appear a bit lengthier than you anticipated, but rest assured that it will fulfill your requirements.

let newArray = []
for(element of originalArray) {
  const currentLabel = element.label
  let labelIndex = -1
  for(let j = 0; j < newArray.length; ++j) {
    if(newArray[j].label === currentLabel) labelIndex = j
  }
  if(labelIndex >= 0) {
    for(let k = 0; k < element.data.length; ++k) {
      const dataKey = Object.keys(element.data[k])
      newArray[labelIndex].data[k][dataKey] = parseInt(newArray[labelIndex].data[k][dataKey])
      newArray[labelIndex].data[k][dataKey] += parseInt(element.data[k][dataKey])
    }
  } else {
    newArray.push(element)
  }
}

const labelOccurrences = originalArray.reduce(function (accumulator, currentElement) {
  return accumulator[currentElement.label] ? ++accumulator[currentElement.label] : accumulator[currentElement.label] = 1, accumulator
}, {});

for(item of newArray) {
  for(dataItem of item.data) {
    dataItem[Object.keys(dataItem)] = (dataItem[Object.keys(dataItem)] / labelOccurrences[item.label]).toFixed(2)
  }
}

Answer №3

Here is a different method that involves using hash grouping twice to generate an intermediate object and then forming a final object.

const data = [{"label":"morning","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"None":"0.00"},{"Netflix":"55.00"},{"Other":"20.00"}]},{"label":"morning","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"None":"0.00"},{"Netflix":"25.00"},{"Other":"0.00"}]},{"label":"morning","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"None":"50.00"},{"Netflix":"50.00"},{"Other":"0.00"}]},{"label":"afternoon","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"None":"50.00"},{"Netflix":"9.00"},{"Other":"20.00"}]},{"label":"afternoon","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"None":"25.00"},{"Netflix":"20.00"},{"Other":"50.00"}]}]

const groups = data.reduce((acc, { label, data }) => {
  acc[label] ??= {};
  data.forEach((item) => {
    const [[channel, value]] = Object.entries(item);
    acc[label][channel] ??= [];
    acc[label][channel].push(Number(value));
  });
  return acc;
}, {});

// groups
//
// {"morning": {
//    "Amazon Prime": [0, 50, 0"],
//    "AppleTV": [0, 0, 0],
//    "HBO Max": [25, 25, 0],
//    "None": [0, 0, 50],
//    "Netflix": [55, 25,50],
//    "Other": [20, 0, 0]},
// ...}

const getFixedAvg = (data) => {
  const average = data.reduce((avg, e) => avg + e) / data.length;
  return (Math.floor(average * 100) / 100) // fix 16.67 to 16.66
    .toFixed(2); 
};

const makeData = (dataObj) => Object.entries(dataObj)
  .map(([channel, dataValues]) => ({ [channel]: getFixedAvg(dataValues) }));
  
const result = Object.entries(groups)
  .map(([label, dataObj]) => ({ label, data: makeData(dataObj) }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }

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

Injecting a full browser-screen DIV into the body of the webpage

Recently, I was tasked with developing a script that could be utilized on any website. As a test, I decided to use the Google search results page. My goal is simple - to have a full-screen semi-transparent div displayed on any site for cookie notification ...

morris.js - displaying a dynamic line chart using JSON data

These are the resources I have: clicks.json index.html The contents of my clicks.json file: [ {"day":1,"clicks":"387"}, {"day":2,"clicks":"432"}, {"day":3,"clicks":"316"}, {"day":4,"clicks":"238"}, {"day":5,"clicks":"354"}, {"da ...

Pagination malfunction on AngularJS md-data-table is causing issues

I have been working on a project that involves retrieving data from an API and displaying it in a table. I am using AngularJS and the md-data-table library by Daniel Nagy. Following the setup instructions, I was able to display my data successfully. Howeve ...

What is the best way to enhance a state's capabilities in Machina.js?

When using Machina.js (version 0.3.6), how can I instantiate a modified FSM constructor where both the child and parent FSMs define behaviors in the same states? Here is the code snippet: var _ = require('lodash'); var machina = require('m ...

Partially accessible Angular service within a callback function

I'm currently facing an issue in my Angular simple app related to a factory that is not fully available within a callback function. You can check out a simplified version of the application on this Plunkr link. Here's a snippet of the code: Th ...

Is it possible to make nested HTML list items align to the left?

Is it possible to align nested HTML list items to the left? For example: Bat Cat Ratonetwothree Mat <ul> <li>Bat</li> <li>Cat</li> <li>Rat<ul><li>one</li><li>two< ...

Obtain the value or values of radio buttons based on certain conditions

Recently, I have been delving into .JS and grappling with pre-existing code. One of the challenges I face involves extracting data from radio buttons after a particular selection is made. The gist of it is related to transportation requirements. Upon indi ...

Using Button Elements to Initiate Server Requests in Node.js

I'm currently in the process of designing a menu for my Node JS application and I'm struggling to find a way to send server requests without relying on the browser's navigation bar. Here is how my directory structure is organized: /applica ...

Steps for transforming a numerical value into an array with individual elements, such that the maximum value in the array will be 1

Can someone assist me? I have a value of 4.8 (it represents a rating of 4.8/5). Now I want to convert it into an array with the following structure: [1, 1, 1, 1, 0.8] What I mean is that the value should be split into 5 elements, with each element not ...

Invoke a functional component when a button is clicked in a React application

I have a functional component that includes a button. My goal is to trigger another functional component when this button is clicked. Upon clicking the Submit button, the Preview button appears. When the user clicks on the preview button, it should call t ...

JSReports encountered an unexpected token "<" in the JSON at position 0

Seeking assistance from those knowledgeable in JSReports, but open to suggestions from all... I've investigated the common issue of "unexpected token < in JSON at position 0", which typically arises when attempting to parse an HTML-formatted strin ...

How to retrieve all the text inside an element using Protractor and Selenium

<div class="test"> <span> <div>CONTENT </div> </span> <div> <ul> <li> <span>More text</span> EXAMPLE1</li> <li>EXAMPLE2</li> ...

Attempting to access a variable from outside the function

I am looking to pass the index variable from mapping to the event change function in my code snippet below: {this.data && this.data.map((item, index) => ( <tr className="table-info" key={index}> <td>{index}</ ...

What makes using $(selector).post() and $.get() in jQuery AJAX so valuable?

While browsing w3school, I came across a discrepancy in the definition of AJAX post and get. Post: $(selector).post(URL,data,function(data,status,xhr),dataType) Get $.get(URL,data,function(data,status,xhr),dataType) Why is there a post method with sel ...

In Next.js, a peculiar issue arises when getServerSideProps receives a query stringified object that appears as "[Object object]"

Summary: query: { token: '[object Object]' }, params: { token: '[object Object]' } The folder structure of my pages is as follows: +---catalog | | index.tsx | | products.tsx | | | \---[slug] | index.tsx | ...

When attempting to import an async function from a separate JavaScript file in NodeJS, it may not be properly

I have a dilemma with two files in my project: getPopular.js and getPlayListByBPM.js. The issue arises when I try to import a function from getPopular.js into getPlayListByBPM.js. Within getPopular.js, I have defined two asynchronous functions: var getPop ...

What is causing the error message 'Unexpected use of 'location' no-restricted-globals'?

When working on my reactjs code, I encountered the following issue: const { children, location: { pathname }, } = this.props; let path = location.pathname; I am also utilizing the react router module in this component. Anyone have suggestions on how ...

What is the most effective way to configure a database for a project that will be utilized across multiple sub-domains, and what is the optimal

Embarking on the development of a large-scale web project meant to be utilized across multiple sub-domains representing different clients has me feeling lost. I am struggling to determine the best or most recommended solution for this type of undertaking. ...

Tips for displaying a message in the model body when a bootstrap model does not have any data in jQuery

Having trouble displaying a text message in the Bootstrap modal body when there is no data available in the model. I have multiple cards in the model, and if I click on the skip or done buttons, each card will close. However, if there is only one card in t ...

Display an icon within an HTML element when the content inside it exceeds its boundaries

Looking to display a copy to clipboard icon when the content inside a div overflows I am using ngFor to iterate through four divs, and if any of those divs is overflowing, I want to show an icon specific to that respective div. <div *ngFor div of Four ...