Exploring potential arrays within a JSON file using TypeScript

Seeking guidance on a unique approach to handling array looping in TypeScript. Rather than the usual methods, my query pertains to a specific scenario which I will elaborate on.

The structure of my JSON data is as follows:

{
    "forename": "Maria",
    "colors": [
      {
        "name": "blue",
        "price": 10
      },
      {
        "name": "yellow",
        "price": 12
      }
    ],
    "items": [
      {
        "name": "sword",
        "price": 20
      }
    ],
    "specialPowers": [
      {
        "name": "telekinesis",
        "price": 34
      }
    ]
  },
  {
    "forename": "Peter",
    "colors": [
      {
        "name": "blue",
        "price": 10
      }
    ],
    "items": [
      {
        "name": "hat",
        "price": 22
      },
      {
        "name": "hammer",
        "price": 27
      }
    ]
  }

  // additional individuals and data

In this setup, each person can possess arrays such as colors, items, or specialPowers. However, it's also possible for a person to have none of these arrays; for instance, Maria has specialPowers but Peter does not.

I am in need of a function that can determine if a person possesses any of these arrays and calculate the total price of all their possessions. In essence, summing up the prices of everything a person owns.

Currently, I have three separate functions structured similarly:

getTotalOfColors(person) {
    let total = 0;
    if(person.colors)
      for (let color of person.colors) {
        total += color.price;
      }
    return total;
  }

getTotalOfItems(person) {
    let total = 0;
    if(person.items)
      for (let item of person.items) {
        total += item.price;
      }
    return total;
  }

 // SIMILAR FUNCTION FOR SPECIALPOWERS

All these functions follow the same process with slight differences due to iterating over different arrays. Is there a more efficient way to consolidate them into one universal function? I envision a single function that iterates through various arrays within a person object, accumulating prices accordingly.

This unified function might resemble the following:

getTotal(person) {
        let total = 0;
        for (let possibleArray of possibleArrays){
          if(person.possibleArray )
            for (let var of person.possibleArray ) {
              total += var.price;
            }
          }
        return total;
      }

To implement this, I believe I would require an array listing the potential arrays like so: possibleArrays = [colors, items, specialPowers]. How can I establish and utilize this array effectively within my code? Alternatively, are there better solutions to address this issue?

Answer №1

After much experimentation, I developed a function that appears to do the job:

function calculateTotalPrice(data) {
  let total = 0;
  for (person of data) {                  //Iterate through the array of people
    for (prop in person) {                //Go through each property of the person
      if (Array.isArray(person[prop])) {  //If the property is an array
        for (element of person[prop]) {   //Go through this array
                                          //Check if `price` is a Number and
                                          //add it to the total
          if (!isNaN(element.price)) total += element.price;
        }
      }
    }
  }

  return total;
}

See the function in action below:

function calculateTotalPrice(data) {
  let total = 0;
  for (person of data) {
    for (prop in person) {
      if (Array.isArray(person[prop])) {
        for (element of person[prop]) {
          if (!isNaN(element.price)) total += element.price;
        }
      }
    }
  }
  
  return total;
}

let data = [
  {
    "forename": "Maria",
    "colors": [{
        "name": "blue",
        "price": 10
      },
      {
        "name": "yellow",
        "price": 12
      }
    ],
    "items": [{
      "name": "sword",
      "price": 20
    }],
    "specialPowers": [{
      "name": "telekinesis",
      "price": 34
    }]
  },
  {
    "forename": "Peter",
    "colors": [{
      "name": "blue",
      "price": 10
    }],
    "items": [{
        "name": "hat",
        "price": 22
      },
      {
        "name": "hammer",
        "price": 27
      }
    ]
  }
];

console.log(calculateTotalPrice(data));

Answer №2

To single out the desired targets, you can utilize the reduce function along with the includes function.

var inputData = [{    "forename": "Maria",    "colors": [{        "name": "blue",        "price": 10      },      {        "name": "yellow",        "price": 12      }    ],    "items": [{      "name": "sword",      "price": 20    }],    "specialPowers": [{      "name": "telekinesis",      "price": 34    }]  },  {    "forename": "Peter",    "colors": [{      "name": "blue",      "price": 10    }],    "items": [{        "name": "hat",        "price": 22      },      {        "name": "hammer",        "price": 27      }    ]  }];

function totalize(possibleArrays, data) {
  return data.reduce((a, c) => {
    return a + Object.keys(c).reduce((ia, k) => {
      if (possibleArrays.includes(k)) c[k].forEach(p => ia += p.price);
      return ia;
    }, 0);    
  }, 0);
}

var total = totalize(["colors", "items", "specialPowers"], inputData);

console.log(total);

Answer №3

If you're looking to calculate the total sum of various properties for each person in your dataset, this code snippet should help. The results are logged in the console, but you can customize how you want to use them:

const getSum = (person, prop) => {
    let total = 0;
    if(person[prop])
      for (let value of person[prop]) {
        total = total + value.price;
      }
    return total;
}

const props = ['colors', 'items', 'specialPowers']

console.log(data.map(person => props.map(prop => getSum(person, prop))));

Edit

Upon further review, it seems like you want to sum up all the properties for one person at once. In that case, this revised code might be more suitable for your needs:

const sum = (a, b) => a + b;

const props = ['colors', 'items', 'specialPowers'] 

data.map(person => 
    props.map(prop =>
        (person[prop] || [])
            .map(({price}) => price)
            .reduce(sum, 0)
    ).reduce(sum, 0)
)

To calculate the total sum of prices for all persons combined, you can use the following code:

data.map(person => 
    props.map(prop =>
        (person[prop] || [])
            .map(({price}) => price)
            .reduce(sum, 0)
    ).reduce(sum, 0)
).reduce(sum, 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

Manipulating datetime format within an input element of type date using Angular's ngModel

I have a date input in my form that is populated from the controller with a string value for 'dateOfDiagnosis'. The format of this string includes the time as well, like this: "2010-09-08T00:00:00" To bind this value to an input field in Angu ...

What could be causing Jquery's $.ajax to trigger all status codes even when the call is successful?

Here is a simple Jquery ajax function call I have. function fetchData(){ var jqxhr = $.ajax({ url: "../assets/js/data/users.json", type: "GET", cache: true, dataType: "json", statusC ...

Determine the number of objects in a JSON array and compile a new array containing the sum of the

I am working with a JSON array that looks like this: const arrayVal = [{ "DATE": "2020-12-1", "NAME": "JAKE", "TEAM_NO": 2, }, { "DATE": "2020-12-2"`, "NAME" ...

What is the best way to retrieve individual elements from an array?

In the controller file, this section is responsible for assigning values to Smarty variables. $objSmarty->assign( 'seleted_customer_subsidy_race_types', $this->getRequestData( array( 'customer_subsidy_race_types' ) ) ); The displ ...

I desire to receive comments only once since they are being rehashed repeatedly

On the server-side: This is where I retrieve the comment from the server db.postSchema .findOne({ _id: comment.post }) .populate("owner") .exec((err, users) => { for (let i = 0; i < ...

Specific category of location on Google Maps

I am currently building an application using Cordova and Ionic. I need to implement a map in my app that will display only specific establishments, such as police stations or doctors' offices. This is the code I have so far: var posOptions = {time ...

I am experiencing issues with icons not loading correctly after changing my module, with error messages indicating issues with cross-origin

Exploring various online tutorials to master the art of Angular programming has been quite an adventure for me. One tutorial introduced a module defined in this manner: .module('MyApp') However, any attempt to modify the name resulted in an er ...

How can I specify the column type when using arrayToDataTable in Google Charts?

When using Google Charts, we have the ability to define column types like date or number by declaring var data = new google.visualization.DataTable();. For example: $dataTable = array ( 'cols' => array ( array('type' =& ...

Using MomentJS along with Timezones to accurately display Datetime while accounting for offsets

I am utilizing moment.js along with timezones to generate a datetime linked to a specific timezone: var datetime = moment.tz("2016-08-16 21:51:28","Europe/London"); Due to the recognition of DST (daylight saving time) by this constructor, moment.js will ...

Enhance the data structure by including extra fields post JSON de-serialization using play-json-extensions

I have a scenario where my case class consists of more than 22 parameters. case class Model(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, ...

Having trouble retrieving the JSON data received from the backend

After making an AJAX request, I receive a response which is then saved to a data variable. This is the controller logic: def retrieve data = params[:data] @question = Question.find_by(id: params[:question_id]) @choices = @question.choices results ...

Refresh the database values every five minutes

I am currently developing a web application that assigns users a ranking based on their activity on Twitter and on my website. For this reason, I want to update their rank every five minutes by retrieving their latest Twitter activity and updating it in m ...

Cycle through images that are dynamically generated from retrieved data

Although I have a functional solution for this issue, it feels messy and not the ideal way to handle it in Vue. The challenge is fetching data from a backend related to a "Vendor" entity, which includes photos that need to be displayed on the page. The go ...

Troubleshooting Angular Build Errors: Integrating Three.js

Upon setting up a new Angular application and integrating three along with @types/three, I proceeded to create a basic component. However, upon executing ng build --prod, the following errors are displayed: ERROR in node_modules/three/src/core/BufferAttri ...

Sending Byte Array Between C# and C++ Using COM Technology

I am new to Component Object Model (COM) and I am facing an issue in passing a byte array from C# to C++. I have successfully passed other data types like strings and integers, but I'm struggling with byte arrays. Any tips on how to achieve this succe ...

Tips for preventing HTML ID clashes while integrating with the Document Object Model of external websites

When incorporating additional HTML elements into a webpage using Javascript or jQuery, along with external CSS declarations, it is important to avoid conflicts with existing IDs and class names already present on the page. This could lead to issues if ther ...

Issue with triggering the change event for <select> tag

Whenever the selected value of the drop down changes, the following code does not work as expected. Please make corrections if any errors are present. <!doctype html> <html lang="en"> <head> <meta charset="utf-8</scri ...

Exploring the best practices for loading state from local storage in VueJS/NuxtJS by leveraging the "useLocalStorage" utility

When attempting to utilize useLocalStorage from pinia, I am encountering an issue where the data in the store's state is not fetched from local storage and instead defaults to the default value. Below is the code snippet from my store method: import ...

Error encountered during Typescript compilation: Type 'void' cannot be assigned to type 'Item[]'

Below are my typescript functions. When I edit in vscode, the second function does not show any error message. However, upon compilation, an error is displayed for the second function: error TS2322: Type 'Promise<void>' is not assignable t ...

Importing Vue and Vuex modules from separate files

Recently, I encountered an uncommon issue. I decided to keep my main.js and store.js files separate in a Vue project. In the store.js file, I imported Vuex, set up a new vuex store, and exported it. However, when importing this file into main.js and settin ...