Get the total value of the matching array elements

This is my current array

0:{modelNumber: "123456789", balance: { amount:1000, currency:"EUR" }}
1:{modelNumber: "987654321", balance: { amount:2000, currency:"EUR" }}
2:{modelNumber: "322353466", balance: { amount:1500, currency:"GBP" }}
3:{modelNumber: "892347522", balance: { amount:1000, currency:"USD" }}
4:{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }}
5:{modelNumber: "854300564", balance: { amount:2500, currency:"GBP" }}
6:{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }}
7:{modelNumber: "854300564", balance: { amount:3500, currency:"USD" }}

I'm trying to return a new array, with each currency and the total value for each currency.

Like below return the total amount for each currency in the array above

0:{currency: "EUR", totalAmount: 3500}
1:{currency: "GBP", totalAmount: 5000}
2:{currency: "USD", totalAmount: 4500}
3:{currency: "INR", totalAmount: 6000}

My approach initially:

//the current array
let theInitialArray = state.vehicle;

const results = theInitialArray.reduce((accumalator, current) => {
    const { currency } = current.balance;
    if (accumalator[currency]) {
        accumalator[currency].push(current);
        return accumalator;
    }
    accumalator[currency] = [current];
    return accumalator;     
}, {});

let frank =  Object.keys(results)
let jim = [];
let expectedOutput = theInitialArray.filter((x) => {
    for (let i=0; i < frank.length; i++) {
        if (x.balance.currency === frank[i]) {
            jim.push({'currency': frank[i], 'amount': x.balance.amount});
        }
    }
});
console.log('expectedOutput', expectedOutput)
return expectedOutput

Upvotes: 10

Views: 605

Answers (7)

Leonid Pyrlia
Leonid Pyrlia

Reputation: 1712

A simple solution with Array.prototype.reduce and Object.keys:

const data = [
    {modelNumber: "123456789", balance: { amount:1000, currency:"EUR" }},
    {modelNumber: "987654321", balance: { amount:2000, currency:"EUR" }},
    {modelNumber: "322353466", balance: { amount:1500, currency:"GBP" }},
    {modelNumber: "892347522", balance: { amount:1000, currency:"USD" }},
    {modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
    {modelNumber: "854300564", balance: { amount:2500, currency:"GBP" }},
    {modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
    {modelNumber: "854300564", balance: { amount:3500, currency:"USD" }}
];

const grouped = data.reduce((o, { balance: { amount:a, currency:c } }) =>
   ({...o, [c]: (o[c] || 0) + a }), {});

const result = Object.keys(grouped).map(currency =>
    ({currency, totalAmount: grouped[currency] }));

console.log(result);

Upvotes: 1

This uses two arrays and pushes the unique names of the currencies in one(currencies) and the objects in another (result).

a = [{modelNumber: "123456789", balance: { amount:1000, currency:"EUR" }}, {modelNumber: "987654321", balance: { amount:2000, currency:"EUR" }},{modelNumber: "322353466", balance: { amount:1500, currency:"GBP" }},{modelNumber: "892347522", balance: { amount:1000, currency:"USD" }},{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},{modelNumber: "854300564", balance: { amount:2500, currency:"GBP" }},{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},{modelNumber: "854300564", balance: { amount:3500, currency:"USD" }}]

let currencies = [], result = [];
a.map((v)=>{
  let {currency, amount} = v.balance;
  if(!currencies.includes(currency)){
    currencies.push(currency);
    result.push({currency, totalAmount:amount});
  }else{
    result[currencies.findIndex(vv=>vv===currency)].totalAmount+=amount;
  }
})

Upvotes: 0

Kliment Ru
Kliment Ru

Reputation: 2137

My solution with native array methods map, filter and reduce

const res = arr
  // map to currency
  .map(i => i.balance.currency)
  // get unique currency
  .filter((v, i, a) => a.indexOf(v) === i)
  // map to result
  .map((i, a) => ({
    currency: i,
    totalAmount: calcTotalAmount(i)
  }));

// calculate amount
function calcTotalAmount(currency) {
  return (
    arr
      // filter to current curency
      .filter(i => i.balance.currency === currency)
      // reduce to number
      .reduce((accum, i) => accum + i.balance.amount, 0)
  );
}

Upvotes: -1

Nina Scholz
Nina Scholz

Reputation: 386604

You could take a Map and render the wanted array of currency/totalAmount pairs as new objects.

var data = [{ modelNumber: "123456789", balance: { amount: 1000, currency: "EUR" } }, { modelNumber: "987654321", balance: { amount: 2000, currency: "EUR" } }, { modelNumber: "322353466", balance: { amount: 1500, currency: "GBP" } }, { modelNumber: "892347522", balance: { amount: 1000, currency: "USD" } }, { modelNumber: "931883113", balance: { amount: 3000, currency: "INR" } }, { modelNumber: "854300564", balance: { amount: 2500, currency: "GBP" } }, { modelNumber: "931883113", balance: { amount: 3000, currency: "INR" } }, { modelNumber: "854300564", balance: { amount: 3500, currency: "USD" } }],
    result = Array.from(
        data.reduce((m, { balance: { amount, currency } }) =>
            m.set(currency, (m.get(currency) || 0) + amount), new Map),
        ([currency, totalAmount]) => ({ currency, totalAmount })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

OliverRadini
OliverRadini

Reputation: 6467

It's possible to reduce the values you have and them map them into the format you require:

const values = [
  {modelNumber: "123456789", balance: { amount:1000, currency:"EUR" }},
  {modelNumber: "987654321", balance: { amount:2000, currency:"EUR" }},
  {modelNumber: "322353466", balance: { amount:1500, currency:"GBP" }},
  {modelNumber: "892347522", balance: { amount:1000, currency:"USD" }},
  {modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
  {modelNumber: "854300564", balance: { amount:2500, currency:"GBP" }},
  {modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
  {modelNumber: "854300564", balance: { amount:3500, currency:"USD" }},
];

const results = values.reduce((prev, curr) => ({
  ...prev,
  [curr.balance.currency]: (prev[curr.balance.currency] || 0) + curr.balance.amount
}), {})

const inCorrectFormat = Object.keys(results).map(key => ({
  currency: key,
  totalAmount: results[key]
}))

console.dir(inCorrectFormat)

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 191976

You can Array.reduce() to iterate the data. If a currency doesn't exist in the accumulator (r in the reduce callback), initialize it. Add the current amount, to the currency amount in the accumulator. Get an array of currencies using Object.values:

const data = [{"modelNumber":"123456789","balance":{"amount":1000,"currency":"EUR"}},{"modelNumber":"987654321","balance":{"amount":2000,"currency":"EUR"}},{"modelNumber":"322353466","balance":{"amount":1500,"currency":"GBP"}},{"modelNumber":"892347522","balance":{"amount":1000,"currency":"USD"}},{"modelNumber":"931883113","balance":{"amount":3000,"currency":"INR"}},{"modelNumber":"854300564","balance":{"amount":2500,"currency":"GBP"}},{"modelNumber":"931883113","balance":{"amount":3000,"currency":"INR"}},{"modelNumber":"854300564","balance":{"amount":3500,"currency":"USD"}}];

const result = Object.values(data.reduce((r, { balance }) => {
  const { amount, currency } = balance;
  if(!r[currency]) r[currency] = { currency, amount: 0 };
  
  r[currency].amount += amount;
  
  return r;
}, {}));

console.log(result);

Upvotes: 8

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

Here is a O(n) approach of getting that output:

  1. You first define a empty object tempObj which will be used to store the currency and totalAmount value as a object based on the currency key
  2. Then, if this currency key is defined in the tempObj you will simply add the amount with the totalAmount for an existing object.
  3. Else you will create a object with the amount as totalAmount, currency as key of tempObj and currency as currency of the item in forEach loop
  4. Finally you will need to do Object.values(tempObj) so that we get the object values and ignore the keys of tempObj to get the desired result.

var arr = [{modelNumber: "123456789", balance: { amount:1000, currency:"EUR" }},
{modelNumber: "987654321", balance: { amount:2000, currency:"EUR" }},
{modelNumber: "322353466", balance: { amount:1500, currency:"GBP" }},
{modelNumber: "892347522", balance: { amount:1000, currency:"USD" }},
{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
{modelNumber: "854300564", balance: { amount:2500, currency:"GBP" }},
{modelNumber: "931883113", balance: { amount:3000, currency:"INR" }},
{modelNumber: "854300564", balance: { amount:3500, currency:"USD" }}];

var tempObj = {};
arr.forEach((obj)=>{
  if(tempObj[obj.balance.currency]){
    tempObj[obj.balance.currency].totalAmount += obj.balance.amount
  } else {
    tempObj[obj.balance.currency] = {
      currency: obj.balance.currency,
      totalAmount : obj.balance.amount
    }
  }
});
var resArray = Object.values(tempObj);
console.log(resArray);

Upvotes: 8

Related Questions