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

Struggling with JavaScript's getElementById function

If anyone has any suggestions or alternative methods, please kindly assist me. I currently have: 1 Textbox 1 Label 1 LinkButton Upon clicking the lnk_NameEdit button, the txtUserName textbox should become visible while the lblusername label should becom ...

Encountering issues with updating state object in setState function

Review the code snippet below: {split.participants.map(friend => { return <div key={Math.random()} className="form-check my-2 d-flex align-items-center justify-content-between"> <div ...

Issue encountered while attempting to load JSON data into Hive

JSON data structure is as follows: {"id":"U101", "name":"Rakesh", "place":{"city":"MUMBAI","state":"MAHARASHTRA"}, "age":20, "occupation":"STUDENT"} {"id":"","name":"Rakesh", "place":{"city":"MUMBAI","state":"MAHARASHTRA"}, "age":20, "occupation":"STUDENT ...

Achieving success despite facing rejection

I am currently utilizing the bluebird settle method in order to verify results for promises without concerning myself with any rejections. Interestingly, even though I have rejected the promise within the secondMethod, the isFulfilled() still returns tru ...

Styling the active selection in nav class with bold attribute in Bootstrap/AngularJs

How can I apply the bold attribute to the currently selected nav bar item? <ul class="nav"> <li role="presentation" ng-repeate="item in items" ng-class="{'active':navLink == item.header}"> </li> &l ...

Extract Data from JSON Array using Jquery

I am working with a JSON array retrieved from a web API, and I need to extract specific values from it. For instance, how can I retrieve all the rides in the first place and access rides[1]. UserID or Images? { "Status":1, "Rides& ...

Discover the power of utilizing JavaScript to sort through table rows by filtering them based on the selections of multiple checkbox

How can I create interdependent logic for checkbox sections in a form to filter based on all selections? I am looking for help with my code snippet that showcases checkboxes controlling the visibility of table rows: $(document).ready(function() { $(" ...

Tips for converting intricate JSON nested data into CSV using Python?

I have a JSON dataset that I need to convert into a CSV file. Can someone assist me with the conversion process? Here is how the JSON dataset looks: { "123456": { "question_data": { "question_title": "How do I ...

Customize the appearance of the Vue.js datepicker starting from today's date

I am currently using the vue-datepicker component to display a date input field in my form. I want to set the default date to the current day and disable the selection of past dates. Additionally, I need to change the language of the component but it seems ...

Having trouble with implementing both filter and infinite scroll simultaneously in an Ionic list?

I've encountered an issue with my ionic hybrid app related to angularjs filters. The code snippet below showcases the problem: <input type="search" placeholder="Search personalities" ng-model="name" ng-change='alert("changed!")&apo ...

How to interrupt a JQuery animation and restart it from the middle?

Currently, I am tackling my first JQuery project and facing a challenge. As the user mouseleaves the .container, the animation does not reset but continues as if they are still within it. My goal is to have the animation revert in reverse if the user decid ...

AngularJS allows for dynamic routing within applications

I'm a beginner with AngularJs and I've run into an issue where the URL changes but the page remains the same. Any help would be greatly appreciated. Here is my configuration: var app = angular.module('MyApp', ['ngResource',& ...

Exploring the power of nested loops within an AJAX call in Angular

I have been attempting to iterate through a variable, search for IDs, and then make an ajax call to retrieve the detailed content of the different IDs. In the Success function, I am trying to loop through the received content and extract the emails. While ...

Using Regex with JavaScript while ignoring letter case

I am trying to extract a query string from my URL using JavaScript, and I need to perform a case-insensitive comparison for the query string name. In order to achieve this, here is the code snippet that I am currently using: var results = new RegExp(&apos ...

Passing a JavaScript Object to an ASP.NET Handler

How can I send a JavaScript object to an ASP.NET Handler and extract its values? I have defined a complex type object as follows: function AccountObjCreate() { var AccountsView = {}; AccountsView.Username = null; AccountsView.Email = null; AccountsView.P ...

The captivating logo animation of Google Chrome

For optimal viewing experience, it is recommended to use Chrome or any WebKit browser. https://www.google.com/intl/en/chrome/browser/ Hovering over the chrome logo reveals an amazing effect. I tried downloading the page source, but got lost in it. The s ...

Using specific sections of JSON data to display in an alert message (Vanilla JavaScript)

I am seeking a bookmarklet that, upon clicking, will access JSON data and retrieve the "temp" information to display in an alert indicating the weather with just one click. Is there a method to achieve this or do I need to utilize a different API? Here&ap ...

What is preventing me from returning a JSON object in Perl script?

I am currently working on a project that incorporates jQuery, AJAX, JSON, and Perl. To handle the backend operations, I am utilizing Perl along with its CGI module to generate a JSON object. #!/usr/software/bin/perl5.8.8 use strict; use warnings; use CGI ...

ng-required is ineffective when used with number inputs that have a minimum value requirement

In my form, I have implemented a checkbox that, when checked, toggles the visibility of a div using AngularJS's ng-show. Within this div, there is an input field of type "number" with a validation setting of min="10000". I am trying to prevent the f ...

Learn how to run a Linux bash command by clicking a button, where the command is generated from user input

HTML: I am presenting two inputs here <input id="range3" type="range" min="0" max="255" value="0" /> <input id="num3" min="0" max="255&q ...