0

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?

8
  • That's an array of objects? Commented Mar 15, 2018 at 13:26
  • @Ele Wel that,s the question. "possibleArrays" is an array which should contain the arrays colors, items, specialPowers. But how do I do this? I tried to do it like this: possibleInsurances = ["colors", "items", "specialPowers"], but of course this won't work because then I would define the arrays as strings, Commented Mar 15, 2018 at 13:33
  • I'm talking about the object you've posted. Commented Mar 15, 2018 at 13:36
  • @Ele I think we can assume it's an array of persons yeah Commented Mar 15, 2018 at 13:38
  • 1
    You've accepted an answer which doesn't meet your requirements: 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] Commented Mar 15, 2018 at 13:45

3 Answers 3

1

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

Sign up to request clarification or add additional context in comments.

9 Comments

In this approach where is this: 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]
@Ele It goes beyond. No need to tell the function what to search, it does it automatically.
@Zenoo so what if there is a property that I don't want to sum ?
No, the OP needs to filter the objects which needs to be added.
@Logar That wouldn't be a function named totalPrice, then, would it ?
|
1

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

Comments

1

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)

2 Comments

Thanks for the edit! I tried it and it also works fine
Glad it helped ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.