简体   繁体   中英

Loop through possible arrays in json with typescript

I'm not asking how to loop through an array in typescript. My question is a bit different so let me explain first.

I have a json which looks like this:

{
    "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
      }
    ]
  }

  // some more persons

As you can see, I have persons which can have arrays like colors, items or specialPowers. BUT a person can also have none of them. As you can see Maria has the array specialPowers, but Peter has not.

I need a function which checks if a person has one of these arrays and if so, I have to sum its price to a total. So I want the total price of all the things a person has.

At the moment I have three functions which basically look like this:

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

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

 // SAME FUNCTION FOR SPECIALPOWERS

I basically have the same function for three times. The only difference is, that I'm looping through another array. But these functions do all the same. They first check, if the person has the array and secondly they loop through this array to add the price to a total.

Finally to my question: Is there a way to do this all in ONE function? Because they all are basically doing the same thing and I don't want redundant code. My idea would be to loop through all the arrays while checking if the person has the array and if so, adding its price to the total.

I assume the function would look something like this:

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

Like this I would have a "universal" function but for that I have to have an array of the possible arrays like this: possibleArrays = [colors, items, specialPowers] How do I achieve this? How and where in my code should I make this array ? Or is there even a better solution for this problem?

I created a function that seems to do the trick:

function totalPrice(data) {
  let total = 0;
  for (person of data) {                  //Go through the array of people
    for (prop in person) {                //Go through every property of the person
      if (Array.isArray(person[prop])) {  //If this 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;
}

Demo:

 function totalPrice(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(totalPrice(data)); 

You can use the function reduce and the function includes to select the desired targets.

 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); 

Something like this should also do it, I just logged the results in console, but you can do pretty much what you want with 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

I didn't get that you wanted to sum up all your properties for one person at once, this code is what I definitely what I would go for :

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)
)

And if you want to sum all person's total price :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM