Sum values from different JSON indices

Asked

Viewed 318 times

4

I have an API that a chunk of it returns the following array, and for each index has an object slas that brings all carriers:

[
  {
    "itemIndex": 0,
    "selectedSla": "Expressa",
    "selectedDeliveryChannel": "delivery",
    "slas": [
      {
        "name": "Expressa",
        "shippingEstimate": "2bd",
        "price": 1390
      },
      {
        "name": "SEDEX",
        "shippingEstimate": "2bd",
        "price": 1990
      },
      {
        "name": "Retira em SÃO PAULO (1936769)",
        "shippingEstimate": "1bd",
        "price": 0
      }
    ]
  },
  {
    "itemIndex": 1,
    "selectedSla": "Expressa",
    "selectedDeliveryChannel": "delivery",
    "slas": [
      {
        "name": "Expressa",
        "shippingEstimate": "2bd",
        "price": 1390
      },
      {
        "name": "SEDEX",
        "shippingEstimate": "2bd",
        "price": 1990
      },
      {
        "name": "Retira em SÃO PAULO (1936769)",
        "shippingEstimate": "1bd",
        "price": 0
      }
    ]
  }
]

I wanted to add up the total value of each carrier.

Example:

0: EXPRESSA 13,90 + 1: EXPRESSA 13,90

0: SEDEX 19,90 + 1: SEDEX 13,90 
  • Could post the exact return of the api, as posted is not valid.

  • @Leandrade json is very extensive so I summarized it in the section that refers.

  • The way it is there is no way to form a correct answer, because there is no way to know the structure of json.

  • @Leandrade Sorry, now json is validated.

  • If the goal is to group by slas there are already questions about this

  • @Isac I found nothing similar, could inform which questions are?!

  • 1

    As an example you can look at this or this

Show 2 more comments

2 answers

7


You can do whatever you want using the methods map() and reduce() as follows:

let retorno = [
  {
    "itemIndex": 0,
    "selectedSla": "Expressa",
    "selectedDeliveryChannel": "delivery",
    "slas": [
      {
        "name": "Expressa",
        "shippingEstimate": "2bd",
        "price": 1390
      },
      {
        "name": "SEDEX",
        "shippingEstimate": "2bd",
        "price": 1990
      },
      {
        "name": "Retira em SÃO PAULO (1936769)",
        "shippingEstimate": "1bd",
        "price": 0
      }
    ]
  },
  {
    "itemIndex": 1,
    "selectedSla": "Expressa",
    "selectedDeliveryChannel": "delivery",
    "slas": [
      {
        "name": "Expressa",
        "shippingEstimate": "2bd",
        "price": 1390
      },
      {
        "name": "SEDEX",
        "shippingEstimate": "2bd",
        "price": 1990
      },
      {
        "name": "Retira em SÃO PAULO (1936769)",
        "shippingEstimate": "1bd",
        "price": 0
      }
    ]
  }
];

let expressa = [];        // arrays que serão guardados os objetos similares
let sedex = [];
let retira = [];

let dados = retorno.map(x => x.slas);          // mapeia os objetos que queremos

expressa = dados.map(x => x[0]);              // insere os objetos similares no array
sedex = dados.map(x => x[1]);
retira = dados.map(x => x[2]);

let valorExpressa = expressa.reduce((a,b) => {   // faz a soma dos valores
  return a + b.price;
},0);

let valorSedex = sedex.reduce((a,b) => {
  return a + b.price;
},0);

let valorRetira = retira.reduce((a,b) => {
  return a + b.price;
},0);

console.log('Valor Expressa: ', valorExpressa);
console.log('Valor SEDEX: ', valorSedex);
console.log('Valor Retira: ', valorRetira);

  • In the case of the carrier array, in some conditions it will be 2 and another 3. E in the future will have more, how to make it dynamic?

  • What do you mean? I don’t understand.

  • you created an array for each carrier, in case there are 3 defined as leaving it dynamic, instead of leaving manual, understood?

  • So, these arrays are the containers for each carrier, I need to create an array for each, if not, I can’t add up the values of each one.

  • Instead of creating an array for each carrier, I will take a single one with all and the value already added, so it is easier to work and dynamic. Thank you so much for your help!

  • Yes, it could be tbm, it is that to give a more conclusive answer, it would need to have a bigger vision of how these data would arrive, it was a way that I saw to do at the time, but, if it managed to solve better. Success there man!

Show 1 more comment

1

I arrived at a solution "dynamics" using only iteration methods of the prototype of Array:

const data = [{
  itemIndex: 0,
  selectedSla: 'Expressa',
  selectedDeliveryChannel: 'delivery',
  slas: [
    { name: 'Expressa', shippingEstimate: '2bd', price: 1390 },
    { name: 'SEDEX', shippingEstimate: '2bd', price: 1990 },
    { name: 'Retira em SÃO PAULO (1936769)', shippingEstimate: '1bd', price: 0 }
  ]
}, {
  itemIndex: 1,
  selectedSla: 'Expressa',
  selectedDeliveryChannel: 'delivery',
  slas: [
    { name: 'Expressa', shippingEstimate: '2bd', price: 1390 },
    { name: 'SEDEX', shippingEstimate: '2bd', price: 1990 },
    { name: 'Retira em SÃO PAULO (1936769)', shippingEstimate: '1bd', price: 0 }
  ]
}];

function getSumFrom(list) {
  return list
    .map((arr) => arr.slas)
    .flat(1) // Juntamos todos os arrays de objetos em um único array de objetos.
    .reduce((acc, current) => {
      const name = current.name;
      const price = current.price;

      // Basicamente, estamos adicionando ao acumulador (`acc`)
      // o nome da empresa. Para isso, estamos somando o valor do
      // preço da iteração atual ao valor já existente.
      //
      // Se o valor existente ainda não existir, consideramos que
      // ele seja zero.
      // (`acc[name] || 0` diz: se `acc[name]` for falsey, assuma zero).
      acc[name] = (acc[name] || 0) + price;
      return acc;
    }, {});
}

console.log(getSumFrom(data));

I tried not to leave the code too complex in the above excerpt to facilitate the reading of the code for those who are starting in the language. But if you are already diving deeper into Javascript, the above code can be reduced:

const data = [{
  itemIndex: 0,
  selectedSla: 'Expressa',
  selectedDeliveryChannel: 'delivery',
  slas: [
    { name: 'Expressa', shippingEstimate: '2bd', price: 1390 },
    { name: 'SEDEX', shippingEstimate: '2bd', price: 1990 },
    { name: 'Retira em SÃO PAULO (1936769)', shippingEstimate: '1bd', price: 0 }
  ]
}, {
  itemIndex: 1,
  selectedSla: 'Expressa',
  selectedDeliveryChannel: 'delivery',
  slas: [
    { name: 'Expressa', shippingEstimate: '2bd', price: 1390 },
    { name: 'SEDEX', shippingEstimate: '2bd', price: 1990 },
    { name: 'Retira em SÃO PAULO (1936769)', shippingEstimate: '1bd', price: 0 }
  ]
}];

function getSumFrom(list) {
  return list
    .flatMap(({ slas }) => slas)
    .reduce(
      (acc, { name, price }) => ({
        ...acc,
        [name]: (acc[name] || 0) + price
      }),
      {}
    );
}

console.log(getSumFrom(data));

I personally prefer this second approach, but this is personal. :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.