JavaScript data manipulation: Determining percentage change within a nested JSON structure

Provided is a JSON file structured like this...

data =[
  {
  key: "london",
  values: [
   {day: "2020-01-01", city: "london", value: 10},
   {day: "2020-01-02", city: "london", value: 20},
   {day: "2020-01-03", city: "london", value: 30},
   {day: "2020-01-04", city: "london", value: 30},
   {day: "2020-01-05", city: "london", value: 30},
   {day: "2020-01-06", city: "london", value: 30}
  ]
  },
  {
  key: "berlin",
  values: [
   {day: "2020-01-01", city: "berlin", value: 10},
   {day: "2020-01-02", city: "berlin", value: 15},
   {day: "2020-01-03", city: "berlin", value: 30},
   {day: "2020-01-04", city: "berlin", value: 30},
   {day: "2020-01-05", city: "berlin", value: 30},
   {day: "2020-01-06", city: "berlin", value: 45}
  ]
  },
  {
  key: "rome",
  values: [
   {day: "2020-01-01", city: "rome", value: 10},
   {day: "2020-01-02", city: "rome", value: 12},
   {day: "2020-01-03", city: "rome", value: 6},
   {day: "2020-01-04", city: "rome", value: 9},
   {day: "2020-01-05", city: "rome", value: 27},
   {day: "2020-01-06", city: "rome", value: 36}
  ]
  }]

I'm interested in calculating the daily percentage change in the series using JavaScript. The expected output would be as follows, with the city information removed for less repetition.

data =[
  {
  key: "london",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-02", value: 20, perc: 1},
   {day: "2020-01-03", value: 30, perc: 1},
   {day: "2020-01-04", value: 30, perc: 0},
   {day: "2020-01-05", value: 30, perc: 0},
   {day: "2020-01-06", value: 30, perc: 0}
  ]
  },
  {
  key: "berlin",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-02", value: 15, perc: 0.5},
   {day: "2020-01-03", value: 30, perc: 1},
   {day: "2020-01-04", value: 30, perc: 0},
   {day: "2020-01-05", value: 30, perc: 0},
   {day: "2020-01-06", value: 45, perc: 0.5}
  ]
  },
  {
  key: "rome",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-02", value: 12, perc: 0.2},
   {day: "2020-01-03", value: 6, perc: -0.5},
   {day: "2020-01-04", value: 9, perc: 0.5},
   {day: "2020-01-05", value: 27, perc: 2},
   {day: "2020-01-06", value: 36, perc: 0.33}
  ]
  }]

Additionally, how can I calculate percentage change for different time intervals (every two days, week, etc.) and achieve an output like the example below? (Displaying percentage change every two days)

data =[
  {
  key: "london",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-03", value: 30, perc: 2},
   {day: "2020-01-05", value: 30, perc: 0},
  ]
  },
  {
  key: "berlin",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-03", value: 30, perc: 2},
   {day: "2020-01-05", value: 30, perc: 0},
  ]
  },
  {
  key: "rome",
  values: [
   {day: "2020-01-01", value: 10, perc: 0},
   {day: "2020-01-03", value: 6, perc: -0.4},
   {day: "2020-01-05", value: 27, perc: 4.5},
  ]
  }]

Answer №1

Here is my unique perspective on the scenario, delving into the additional query.

Feel free to reach out with any queries - this marks my debut on stackoverflow!

// Here lies your initial dataset
const data = [
  {
    key: "paris",
    values: [
      {day: "2020-01-01", city: "paris", value: 15},
      {day: "2020-01-02", city: "paris", value: 25},
      {day: "2020-01-03", city: "paris", value: 35},
      {day: "2020-01-04", city: "paris", value: 45},
      {day: "2020-01-05", city: "paris", value: 55},
      {day: "2020-01-06", city: "paris", value: 65}
    ]
  },
  // Add additional city data here if needed
];

// Parsing and manipulating the input data
const processedData = data.map((obj) => {
  return {...obj, values: obj.values.map((value, i) => {
    delete value['city'];

    if (i === 0)
       return { ...value, perc: 0 };

    const currentValue = value.value;
    const currentDay = new Date(value.day);

    const previousValue = obj.values[i-1].value;
    const previousDay = new Date(obj.values[i-1].day);

    const dayTimeDiff = Math.abs(currentDay - previousDay);
    const dayDiff = Math.ceil(dayTimeDiff / (1000 * 60 * 60 * 24));

    const percentDiff = (currentValue - previousValue) / previousValue / dayDiff;

    return { ...value, perc: percentDiff };
  })}
});

console.log(processedData);

Answer №2

To start off, you have the ability to modify each value within the values array:

const data = [
  {
  key: "paris",
  values: [
   {day: "2020-01-01", city: "paris", value: 10},
   {day: "2020-01-02", city: "paris", value: 20},
   {day: "2020-01-03", city: "paris", value: 30},
   {day: "2020-01-04", city: "paris", value: 30},
   {day: "2020-01-05", city: "paris", value: 30},
   {day: "2020-01-06", city: "paris", value: 30}
  ]
  },
  {
  key: "madrid",
  values: [
   {day: "2020-01-01", city: "madrid", value: 10},
   {day: "2020-01-02", city: "madrid", value: 15},
   {day: "2020-01-03", city: "madrid", value: 30},
   {day: "2020-01-04", city: "madrid", value: 30},
   {day: "2020-01-05", city: "madrid", value: 30},
   {day: "2020-01-06", city: "madrid", value: 45}
  ]
  },
  {
  key: "amsterdam",
  values: [
   {day: "2020-01-01", city: "amsterdam", value: 10},
   {day: "2020-01-02", city: "amsterdam", value: 12},
   {day: "2020-01-03", city: "amsterdam", value: 6},
   {day: "2020-01-04", city: "amsterdam", value: 9},
   {day: "2020-01-05", city: "amsterdam", value: 27},
   {day: "2020-01-06", city: "amsterdam", value: 36}
  ]
  }]

const newData = data.map((info) => {

      const n = info.values.length;
      const valuesCopy = info.values.map((info) => info.value);

      for (let i = 0; i < n; i++) {

         const currentValue = valuesCopy[i];
         const previousValue = valuesCopy[i - 1];
         // calculate the percentage
         const percentage = (currentValue - previousValue) / previousValue;

        // if percentage is NaN, return 0
        // if percentage is less than 1, return 2 decimal places
        // otherwise return percentage
        info.values[i].value = !percentage ? 0 : percentage < 1 ? percentage.toFixed(2) : percentage;
      }

    return info;
  })

 console.log(JSON.stringify(newData, null, 2));

Answer №3

Here's a demonstration using basic for loops along with comments:

const data =[
  {
  key: "paris",
  values: [
   {day: "2021-01-01", city: "paris", value: 12},
   {day: "2021-01-02", city: "paris", value: 22},
   {day: "2021-01-03", city: "paris", value: 32},
   {day: "2021-01-04", city: "paris", value: 34},
   {day: "2021-01-05", city: "paris", value: 36},
   {day: "2021-01-06", city: "paris", value: 38}
  ]
  },
  {
  key: "madrid",
  values: [
   {day: "2021-01-01", city: "madrid", value: 18},
   {day: "2021-01-02", city: "madrid", value: 23},
   {day: "2021-01-03", city: "madrid", value: 35},
   {day: "2021-01-04", city: "madrid", value: 37},
   {day: "2021-01-05", city: "madrid", value: 39},
   {day: "2021-01-06", city: "madrid", value: 42}
  ]
  }
];

// Initialize an empty array for results
const results = [];

// Iterate through the data
for(let i = 0; i < data.length; i++) {
  // Create a new object for the city
  const city = {
    key: data[i].key,
    values: []
  };
  
  // Shortcut to access the values
  const dVal = data[i].values
  
  // Loop through the values in each city entry
  for(let j = 0; j < dVal.length; j++) {
    // Set previous value or current if it is the first cycle
    const prev = (j !== 0) ? dVal[j-1].value : dVal[j].value;
    // Current value
    const cur = dVal[j].value;
    // Calculate percentage difference
    let percDiff = (cur - prev) / prev;
    // Limit to two decimal places
    percDiff = parseFloat(percDiff.toFixed(2));
    // Add to city object
    city.values.push({
      day: dVal[j].day,
      value: dVal[j].value,
      perc: percDiff
    });
  }
  
  // Add city object to results array
  results.push(city);
}

// Display results
console.log(results);

In response to your second question, simply remove unnecessary day entries from the array and then pass the updated array to the same function. It will calculate the difference between entries whether it is daily or weekly.

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

Tips for Disabling ML5 Posenet

Looking to halt Posenet after completing app task private sketch(p: any) { p.setup = () => { this.poseNet = ml5.poseNet(p.createCapture(p.VIDEO), { outputStride: 8 }); this.poseNet.on(&apos ...

Developing Attributes in JSON

Greetings stackOverflow Community, I'm struggling a bit with creating JSON objects. I have code snippet that is meant to populate a list called members with names, and then add a property to each of those names. Here is the specific snippet in questi ...

Is there a way to sort through a data object using a state array in React?

I have found a solution! The code below now displays a functioning example. My latest project involves creating a React portfolio with a Filter system. Users can visit the portfolio page and choose filters (web design, development, etc.) to view specific ...

Exploring the Node Promise Chain: Utilizing Local Functions and Managing Multiple Value Passing in a Code Review

Upon reviewing the code provided, several questions have arisen: #1 I am curious about the best way to make the values returned by the bluebird.all functions accessible in subsequent functions. Is using the this-context a viable option without declaring t ...

A guide to creating an HTTPS request using node.js

I am currently in the process of developing a web crawler. Previously, I utilized the following code for HTTP requests: var http=require('http'); var options={ host:'http://www.example.com', path:'/foo/example' }; ...

Refreshing a Nested Component Within a Parent Component in React

Currently, I am in the final stage of a small project where a Higher Order Component (HOC) is being utilized to display a basic Tinder-like application. The internal component is a class-based component containing its own fetch() call that presents user d ...

Exploring the wonders of retrieving JSON data in PHP through an Ajax request

A front-end developer is sending an array of data formatted as a JSON object using an Ajax call. The JSON object structure is shown below: { "name": " Test Name ", "image_url": "test URL", "include": [ "1" ], "dimension": [ null ], "media_type" ...

Issue with MUI Autocomplete not showing selected name on initial option selection

I encountered a strange issue with the Autocomplete component from Material UI. Here is the code snippet in question: const [isContactListInitialised, setContactListInitialised] = useState(false); const toggleContactListInitialized = () => { setContactL ...

How can I unravel a JSON array of tuples in Jq to create numerous individual elements?

Looking for a way to parse this complex json data: {"op":"mcm","clk":"1147179697","pt":1439869512969, "mc":[ {"id":"1.120040663", "rc":[ {"atb":[[7.6,35],[7.2,25]],"id":11111}, {"atb":[[1.04,100],[1.02,200 ...

In React Js, I have noticed that when I incorporate a Select field, it only works when the value is an integer and not a string. It seems

Library version "material-ui": "^1.0.0-beta.35" react version: "react": "^16.2.0" Currently Functional: <MenuItem value={1}>Text</MenuItem> <MenuItem value={2}>Integer</MenuItem> <MenuItem value={3}>Inline</MenuItem> N ...

Nextjs optimizing page caching to reduce unnecessary rendering

Within my Next.js application, I have implemented two unique pages. Each page is designed to display a randomly selected person's name when the component is initially loaded. simpsons.tsx export default function Simpsons() { const [person, setPerso ...

Executing a webservice method in an html page using javascript without the need to refresh the page

Is it possible to call a webservice from an index.html page using JavaScript? My webservice is located at "localhost/ws/service.asmx" and the specific web method I want to call is called HelloWorld. The index.html page contains an HTML submit button whic ...

Unable to configure Struts2 result to output in JSON format

Using json with Struts2 is my goal. However, I encountered an issue when setting the action return type to "json". The error message received was "there is no result type defined for type 'json' mapped with name 'success'." Below is a s ...

What could be causing my Angular.js application to malfunction on IE7?

I have developed an Angular.js application that is working well on most browsers, but I am now facing compatibility issues with IE 7 and above. I have tried different approaches such as adding id="ng-app", using xmlns:ng, manually bootstrapping angular wi ...

Adjusting firebugx.js for compatibility with Internet Explorer Developer Tools

The firebugx.js file (viewable at http://getfirebug.com/firebug/firebugx.js) is designed to detect the installation of Firebug by checking both !window.console and !console.firebug. However, this method does not account for the native console object in the ...

The 'BaseResponse<IavailableParameters[]>' type does not contain the properties 'length', 'pop', etc, which are expected to be present in the 'IavailableParameters[]' type

After making a get call to my API and receiving a list of objects, I save that data to a property in my DataService for use across components. Here is the code snippet from my component that calls the service: getAvailableParameters() { this.verifi ...

Setting up Quasar plugins without using Quasar CLI: A step-by-step guide

I integrated Quasar into my existing Vue CLI project by running vue add quasar. Now I'm attempting to utilize the Loading plugin, but unfortunately, it's not functioning as expected. Here is the configuration setup for Quasar/Vue that I have in ...

Utilize JavaScript to extract content from a text file and showcase it in a Bootstrap modal pop-up through knockout binding

I'm currently working on a function that reads data from a .txt file (located in the website's root directory) and then displays it in a modal dialog box. I believe I've made progress as the file is recognized during debugging, but unfortuna ...

What causes non-reactive variables to act unusual in Vue3?

Check out this code snippet: <template> <input type="button" value="click" @click="clickBtn"/> <div id="reactiveDiv">{{ reactiveVariable }}</div> <div id="noneReactiveDiv"&g ...

405 status code returned for CORS request

Hello everyone, I need assistance with my CORS issue. I am trying to make an API request from another domain and encountering an error with the following code: var headers = { host: host, path: url + instance + '?action=reset', ...