最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Get the total value of the matching array elements - Stack Overflow

programmeradmin3浏览0评论

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

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
Share Improve this question edited Sep 22, 2018 at 17:16 themanwiththemasterplan asked Sep 18, 2018 at 8:35 themanwiththemasterplanthemanwiththemasterplan 4112 gold badges7 silver badges23 bronze badges 1
  • 2 Would you also consider { "EUR": 3000, "GBP": 4000, "USD": 4500, "INR": 6000 } as output? It would hold the exact same information and would be much easier to work with. – Eric Duminil Commented Sep 18, 2018 at 11:21
Add a comment  | 

7 Answers 7

Reset to default 8

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

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

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

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)

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

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

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)
  );
}
发布评论

评论列表(0)

  1. 暂无评论