How to summarize total number in an array object - javascript

const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const res = dataAll.map((singleData) => singleData.data.slp.total);
const theres = JSON.stringify(res);
console.log(theres);
How can I add up all the total numbers from the array above?
so I can get the total of 3 + 6 + 5 = 14
and to get a number of the total number of an array in .length total of 3 example

You can easily add them using reduce and take the length as dataAll.length
const dataAll = [
{ id: 1, slp: { total: "3" } },
{ id: 2, slp: { total: "6" } },
{ id: 3, slp: { total: "5" } },
];
const total = dataAll.reduce((acc, curr) => +curr.slp.total + acc, 0);
const length = dataAll.length;
console.log(total, length);

try this:
const dataAll = [{ id: 1, slp: { total: '3' } }, { id: 2, slp: { total: '6' } }, { id: 3, slp: { total: '5' } }]
let total = 0
dataAll.map((singleData)=>{
total += parseInt(singleData.slp.total)
})
//Use whatever hook you need here to store the total value
setTotalHook(total, dataAll.length)
console.log(total)

You can use reduce to sum up values in an array.
const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const res = dataAll.reduce((partial_sum, a) => partial_sum + parseInt(a.slp.total), 0);
const theres = JSON.stringify(res);
console.log(theres);

For length just check the length property of the array.
To sum up the totals you can use reduce to iterate over the array of objects and add the value of total to the accumulator (initially set to zero) on each iteration. Note: you need to coerce that value to a number.
const data = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ];
const sum = data.reduce((acc, c) => {
// Coerce the string value to a number
// and add it to the accumulator
return acc + Number(c.slp.total);
}, 0);
console.log(`Length: ${data.length}`);
console.log(`Sum: ${sum}`);

You should be able to use reduce.
const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const sum = dataAll.reduce(((total, b) => total + parseInt(b.slp.total, 10)), 0);
const totalElements = dataAll.length;
console.log(sum, totalElements)

Related

Efficient way to get top count of an option in an array of objects

I have an array of objects like this,
[
{
user: 'A',
answers: [
{
id: 1,
score: 3,
},
{
id: 2,
score: 1,
},
...
]
},
{
user: 'B',
answers: [
...
where I have 200 users, each user answers a set of 40 questions, each question has an id and a score.
What I'm trying to do is add up each question's score. So that I can figure out which question has the highest score, which has the lowest. Aka, top question and bottom question.
What would be the best way to do this?
The current way I am doing feels a little long-winded.
const allAns = []
myList.forEach( user => allAns.push( ...user.answers ) )
const questionsScored = allAns.reduce( ( obj, cur ) => {
!obj[ cur.id ] ? obj[ cur.id ] = cur.score : obj[ cur.id ] += cur.score
return obj
}, {} )
const sortingList = []
for ( const qn in questionsScored ) {
sortingList.push( [ qn, questionsScored[ qn ] ] )
}
sortingList.sort( ( a, b ) => b[ 1 ] - a[ 1 ] )
console.log( sortingList[ 0 ], sortingList[ sortingList.length - 1 ] )
You're taking all the steps necessary so if it's working it's fine though you could replace some of your forEach() loops with available methods:
with .flatMap()
const allAns = myList.flatMap(({answers})=>answers);
and using Object.entries()
const sortingList = Object.entries(questionsScored);
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
allAns = input.flatMap(({ answers }) => answers),
questionsScored = allAns.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {}),
sortingList = Object.entries(questionsScored).sort((a, b) => b[1] - a[1]);
console.log({ max: sortingList[0], min: sortingList[sortingList.length - 1] })
Or combined into a single chained call, but it's not necessarily better.
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
sortingList = Object
.entries(
input
.flatMap(({ answers }) => answers)
.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {})
)
.sort((a, b) => b[1] - a[1]);
console.log({ max: sortingList[0], min: sortingList[sortingList.length - 1] })
If you would like to avoid the sort() call you can instead collect the low and high counts using a forEach() after the initial reduce()
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
lowScore = { count: Infinity },
highScore = { count: -Infinity };
Object
.entries(
input
.flatMap(({ answers }) => answers)
.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {})
)
.forEach(([id, count]) => {
// update low count
if (count < lowScore.count) {
lowScore.count = count;
lowScore.id = id;
}
// update high count
if (count > highScore.count) {
highScore.count = count;
highScore.id = id;
}
});
console.log({ lowScore, highScore })
// sample data
let data = [{
user: 'A',
answers: [{
id: 1,
score: 1,
},
{
id: 2,
score: 2,
},
{
id: 3,
score: 3,
},
{
id: 4,
score: 4,
},
]
},
{
user: 'B',
answers: [{
id: 1,
score: 1,
},
{
id: 2,
score: 2,
},
{
id: 3,
score: 3,
},
{
id: 4,
score: 4,
},
]
},
]
let scoreSum = []; //scoreSum to store total score of each question
let initialValue = 0;
for (let i = 0; i < 4; i++) {
let sum = data.reduce(function (accumulator, currentValue) {
return accumulator + currentValue.answers[i].score;
}, initialValue)
scoreSum.push(sum);
}
let highestScore = Math.max(...scoreSum);
let lowestScore = Math.min(...scoreSum);
// increasing index by 1 to match with question numbers
let highestScoreIndex = scoreSum.indexOf(highestScore) + 1;
let lowestScoreIndex = scoreSum.indexOf(lowestScore) + 1;
// Array.prototype.getDuplicates returns an object where the keys are the duplicate entries
// and the values are an array with their indices.
Array.prototype.getDuplicates = function () {
var duplicates = {};
for (var i = 0; i < this.length; i++) {
if (duplicates.hasOwnProperty(this[i])) {
duplicates[this[i]].push(i);
} else if (this.lastIndexOf(this[i]) !== i) {
duplicates[this[i]] = [i];
}
}
return duplicates;
};
let sameScore = scoreSum.getDuplicates();
// checking if highest score has duplicates
// and if so then updaing highest score index
//with highest score indices
if (sameScore.hasOwnProperty(highestScore)) {
highestScoreIndex = sameScore[highestScore].map((a) => a + 1);
}
// checking if lowest score has duplicates
// and if so then updaing lowest score index
//with lowest score indices
if (sameScore.hasOwnProperty(lowestScore)) {
lowestScoreIndex = sameScore[lowestScore].map((a) => a + 1);
}
console.log(`Top question no(s): ${highestScoreIndex} highest score:${highestScore}`);
console.log(`bottom question no(s): ${lowestScoreIndex} lowest score:${lowestScore}`);
I only loop once through each answer in .answers for each user using nested reduce.
The input array got three users with each three answers.
let input = [{ user: 'A', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 4, }, { id: 3, score: 0, }] }, { user: 'c', answers: [{ id: 1, score: 0, }, { id: 2, score: 3, }, { id: 3, score:5, }] }]
function showBestAndWorstFrom(input) {
let highestScore = {'id': 0, 'score': -Infinity};
let lowestScore = {'id': 0, 'score': Infinity};
let currentScore = 0;
let id = 0;
const LAST_USER = input.length - 1;
let answers = input.reduce((combinedObj, user, userIndex) => {
return user.answers.reduce((_answerObj, _answer) => {
id = _answer.id
currentScore = (_answerObj[id] || 0) + _answer.score;
_answerObj[id] = currentScore;
if (userIndex == LAST_USER) {
highestScore = (highestScore.score < currentScore) ? {'id': id, 'score': currentScore } : highestScore;
lowestScore = (lowestScore.score > currentScore) ? {'id': id, 'score': currentScore } : lowestScore;
}
return _answerObj;
}, combinedObj);
}, {});
// console.log(answers); // { "1": 4, "2": 8, "3": 5 }
return {highestScore, lowestScore};
}
console.log(showBestAndWorstFrom(input))

Find objects with same prop and return the update value with its associated prop [duplicate]

I have javascript array object as below. My need is to sum value base on seach id in the array object.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
],
For example sum of value for id 1 is 10 + 30 + 25 + 20 = 85 , It may be something link linq but I'm not sure in javascript. Thanks for all answers.
You can use a combination of filter and reduce to get the result you want:
sumOfId = (id) => array.filter(i => i.id === id).reduce((a, b) => a + b.val, 0);
Usage:
const sumOf1 = sumOfId(1); //85
Reading material:
Array.prototype.filter
Array.prototype.reduce
A way to do it with a traditional for loop
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sums = {};
for (var i = 0; i < array.length; i++) {
var obj = array[i];
sums[obj.id] = sums[obj.id] === undefined ? 0 : sums[obj.id];
sums[obj.id] += parseInt(obj.val);
}
console.log(sums);
running example
You can use reduce() and findIndex()
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
let res = array.reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
ind === -1 ? ac.push(a) : ac[ind].val += a.val;
return ac;
},[])
console.log(res);
JS noob here ... I guess something like this should be here too :-)
let newArray = {}
array.forEach((e) => {
!newArray[e.id] && (newArray[e.id] = 0);
newArray[e.id] += e.val;
});
You can loop on the array and check the ids.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sum = 0;
var id = 1;
$.each(array, function(index, object){
if (object.id == id) {
sum += object.val;
}
});
console.log(sum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using Array#reduce and Map you can get the sum for each id like so. This also uses destructuring to have quicker access to properties.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
console.log(res.get(1));
console.log(res.get(2));
If you wanted to output all the sums, then you need to use Array#from
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
);
console.log(res);
If the format should be similar as to your original structure, you need to add a Array#map afterwards to transform it.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
).map(([id,sum])=>({id,sum}));
console.log(res);
You could take GroupBy from linq.js with a summing function.
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }],
result = Enumerable
.From(array)
.GroupBy(null, null, "{ id: $.id, sum: $$.Sum('$.val') }", "$.id")
.ToArray();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
Here is another option, introducing an Array.prototype.sum helper:
Array.prototype.sum = function (init = 0, fn = obj => obj) {
if (typeof init === 'function') {
fn = init;
init = 0;
}
return this.reduce(
(acc, ...fnArgs) => acc + fn(...fnArgs),
init
);
};
// .sum usage examples
console.log(
// sum simple values
[1, 2, 3].sum(),
// sum simple values with initial value
[1, 2, 3].sum(10),
// sum objects
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(obj => obj.a),
// sum objects with initial value
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(10, obj => obj.a),
// sum custom combinations
[{ amount: 1, price: 2 }, { amount: 3, price: 4 }]
.sum(product => product.amount * product.price)
);
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }];
// solutions
console.log(
array.filter(obj => obj.id === 1).sum(obj => obj.val),
array.filter(({id}) => id === 1).sum(({val}) => val),
array.sum(({id, val}) => id === 1 ? val : 0)
);
references:
Array.prototype.reduce
Array.prototype.filter
Arrow functions used in sum(obj => obj.val)
Object destructing assignment used in ({id}) => id === 1
Rest parameters used in (acc, ...fnArgs) => acc + fn(...fnArgs)
Conditional (ternary) operator used in id === 1 ? val : 0

reduce array of array into a flat array of object

I'm stuck at transforming a data structure:
let d = [
{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[
{ no: 1, score: 8500 },
{ no: 2, score: 6500 }
]
];
d = d.reduce((accum, o) => {
}, [])
How can I produce this?
[{name: 'no 1', score: [7000, 8500]}, {name: 'no 2', score: [10000, 6500]}]
Here is one way to do it with simple reduce,
const result = d.flat().reduce((acc: {name: string, score: number[]}[], curr) => {
const { no, score } = curr;
let item = acc.find(a => a.name === `no ${no}`);
if (!item) {
item = { name: `no ${no}`, score: []};
acc.push(item);
}
item.score.push(score);
return acc;
}, []);
console.log(result)
let d = [{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[ { no: 1, score: 8500 },
{ no: 2, score: 6500 }]]
const result=d.flat().reduce((acc,curr)=>{
if(acc[curr.no]){
acc[curr.no].score.push(curr.score)
} else {
const keys=Object.keys(curr)
acc[curr.no]={ name: keys[0]+ ' '+curr.no, score:[curr.score]}
}
return acc;
},{})
console.log(Object.values(result))
Array.prototype.flat() call before the actual grouping, then use reduce function create the result.
let d = [{
no: 1,
score: 7000
},
{
no: 2,
score: 10000
},
[{
no: 1,
score: 8500
},
{
no: 2,
score: 6500
}
]
]
const result = d.flat().reduce((result, element) => {
const key = element.no;
if (!result[key]) {
result[key] = {
name: `no ${key}`,
score: []
}
}
result[key].score.push(element.score);
return result;
}, {})
console.log(Object.values(result))
Here's a sleek functional solution for typescript, since you included the tag-
const arr = [
{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[
{ no: 1, score: 8500 },
{ no: 2, score: 6500 },
],
];
const result = Object.entries(
arr.flat().reduce((accum: { [key: number]: number[] }, el: { no: number; score: number }) => {
accum[el.no] = (accum[el.no] ?? []).concat(el.score);
return accum;
}, {})
).map(([num, scores]) => ({ no: Number(num), scores: scores }));
console.log(result);
Result-
[
{ no: 1, scores: [ 7000, 8500 ] },
{ no: 2, scores: [ 10000, 6500 ] }
]
This flattens the inner arrays first using Array.prototype.flat. Then it uses reduce to construct an object that has the no values as keys and score values as an array of values.
In the end, the reduce results in { 1: [7000, 8500], 2: [10000, 6500] } - turn that into entries using Object.entries to get [['1', [7000, 8500]], ['2', [10000, 6500]]]
Finally, map over the entries to turn the ['1', [7000, 8500]] format into { no: 1, scores: [ 7000, 8500 ] } format and you're done!
You could take a dynamic approach which groups by the given key and takes all other properties for a new array.
const
groupBy = key => (r, value) => {
if (Array.isArray(value)) return value.reduce(group, r);
const { [key]: _, ...o } = value;
Object.entries(o).forEach(([k, v]) => ((r[_] ??= { [key]: _ })[k] ??= []).push(v));
return r;
}
data = [{ no: 1, score: 7000 }, { no: 2, score: 10000 }, [{ no: 1, score: 8500 }, { no: 2, score: 6500 }]],
group = groupBy('no'),
result = Object.values(data.reduce(group, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.flat()
or if you have any array like,
let d = [
{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[
{ no: 1, score: 8500 },
{ no: 2, score: 6500 }
]
];
and then use d.flat()
Try this:
let d = [
{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[
{ no: 1, score: 8500 },
{ no: 2, score: 6500 }
]
]
const reducer = (arr, start = []) => arr.reduce((acc, next) => {
if (Array.isArray(next)) return reducer(next, acc);
for (const value of acc) {
if (value.name === `no ${next.no}`) {
value.score = [...value.score, next.score];
return acc;
}
}
return [...acc, {
name: `no ${next.no}`,
score: [next.score]
}];
}, start);
console.log(reducer(d));
In your case, you not only need to flatten the list, but also group by no property.
For flatting, you can use Array.prototype.flat(). It's quite a new feature, so if you don't use polyfills, you probably can't use it. So you can check for alternative implementations.
For grouping, you can reduce to the object where the key is no property. Note, that if multiple no properties exist, you need to save an array of all score values.
Example:
const d = [{ no: 1, score: 7000 },
{ no: 2, score: 10000 },
[ { no: 1, score: 8500 },
{ no: 2, score: 6500 }]]
const grouped = d.flat().reduce((prev, cur) => {
if (cur.no in prev) {
prev[cur.no].score.push(cur.score)
} else {
prev[cur.no] = {
name: 'no ' + cur.no,
score: [cur.score]
}
}
return prev
}, {})
console.log(Object.values(grouped))
In the example we use modifications. It is possible to do it without modifications - return a new copy during each reduction iteration. However, depending on array size, there can be performance issues. Also, it's safe to do modifications, because we create a new object in this case.

How to compare key with sum of array of objects' keys?

I have arrays of objects ob1 and ob2 and I want to check whether the total quantity total of each object is be equal with the sum of the qtys of the objects in the info array.
if total = sum(info.qty) for all objects then return an empty array otherwise return the objects with the invalid total fields.
My attempt so far:
function checktotal(ob1) {
var result = ob1.forEach(e => {
if (e.info.length > 0) {
var sum = e.info.reduce((a, {qty}) => a + qty, 0);
if (sum !== e.total) {
return "total qty not matches with info total qty,"+e
}
})
}
var ob1 = [
{id:1, total: 2, info:[{idx:1, qty:1},{idx: 2, qty: 2}] },
{id:2, total:1, info: [{idx:1, qty:1}] };
];
var ob2 = [
{id:1, total: 1, info:[{idx:1, qty:1}] },
{id:2, total:4, info: [{idx:1, qty:2},{idx: 2, qty: 2}] };
];
Expected Output:
checktotal(ob1); // should return [{id:1, total:2, info:[{idx:1, qty:1}, {idx:2, qty:2}]}]
checktotal(ob2); // should return []
You can filter the records by comparing total and getting total of info qty by making use of reduce(). Here is a working example
var ob1 =[
{id:1, total: 2, info:[{idx:1, qty:1},{idx: 2, qty: 2}] },
{id:2, total:1, info: [{idx:1, qty:1}]}
];
var result = ob1.filter(k=>k.total!=k.info.reduce((a, {qty})=>a+qty,0));
console.log(result);
I hope this will lead you towards right direction.
Working commented example:
// finds total sum of qtys in info array
function totalSum(infoArray) {
return infoArray.reduce((acc, info) => acc + info.qty, 0);
}
// returns items with incorrect totals
function checkTotal(itemArray) {
return itemArray.filter(item => item.total !== totalSum(item.info));
}
let ob1 = [
{id:1, total:2, info:[{idx:1, qty:1}, {idx:2, qty:2}]}, // incorrect total
{id:2, total:1, info:[{idx:1, qty:1}]}, // correct total
];
let ob2 = [
{id:1, total:1, info:[{idx:1, qty:1}]}, // correct total
{id:2, total:4, info:[{idx:1, qty:2}, {idx: 2, qty: 2}]}, // correct total
];
console.log(checkTotal(ob1)); // returns 1st item
console.log(checkTotal(ob2)); // returns empty array
I think you are looking for a function that returns the subset of objects from an input array of objects for which the total amount in total does not equal the sum of the amounts in qty in the objects inside info.
You can use filter() to get the array of mismatching objects, and the condition to check the sum makes use of reduce(). Below is a working example.
Please note that unlike what you requested, the call on the first array of objects returns an array that contains the culprit object, instead of just the object itself.
function checkTotal(data) {
return data.filter(({ total, info }) => (
total !== info.reduce((acc, { qty }) => (acc + qty), 0)
));
}
var ob1 = [
{ id: 1, total: 2, info: [{ idx: 1, qty: 1 }, { idx: 2, qty: 2 }] },
{ id: 2, total: 1, info: [{ idx: 1, qty: 1 }] }
];
var ob2 = [
{ id: 1, total: 1, info: [{ idx: 1, qty: 1 }] },
{ id: 2, total: 4, info: [{ idx: 1, qty: 2 }, { idx: 2, qty: 2}] }
];
console.log('ob1', checkTotal(ob1));
console.log('ob2', checkTotal(ob2));

How to sum value in javascript array object form specific search id?

I have javascript array object as below. My need is to sum value base on seach id in the array object.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
],
For example sum of value for id 1 is 10 + 30 + 25 + 20 = 85 , It may be something link linq but I'm not sure in javascript. Thanks for all answers.
You can use a combination of filter and reduce to get the result you want:
sumOfId = (id) => array.filter(i => i.id === id).reduce((a, b) => a + b.val, 0);
Usage:
const sumOf1 = sumOfId(1); //85
Reading material:
Array.prototype.filter
Array.prototype.reduce
A way to do it with a traditional for loop
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sums = {};
for (var i = 0; i < array.length; i++) {
var obj = array[i];
sums[obj.id] = sums[obj.id] === undefined ? 0 : sums[obj.id];
sums[obj.id] += parseInt(obj.val);
}
console.log(sums);
running example
You can use reduce() and findIndex()
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
let res = array.reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
ind === -1 ? ac.push(a) : ac[ind].val += a.val;
return ac;
},[])
console.log(res);
JS noob here ... I guess something like this should be here too :-)
let newArray = {}
array.forEach((e) => {
!newArray[e.id] && (newArray[e.id] = 0);
newArray[e.id] += e.val;
});
You can loop on the array and check the ids.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sum = 0;
var id = 1;
$.each(array, function(index, object){
if (object.id == id) {
sum += object.val;
}
});
console.log(sum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using Array#reduce and Map you can get the sum for each id like so. This also uses destructuring to have quicker access to properties.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
console.log(res.get(1));
console.log(res.get(2));
If you wanted to output all the sums, then you need to use Array#from
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
);
console.log(res);
If the format should be similar as to your original structure, you need to add a Array#map afterwards to transform it.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
).map(([id,sum])=>({id,sum}));
console.log(res);
You could take GroupBy from linq.js with a summing function.
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }],
result = Enumerable
.From(array)
.GroupBy(null, null, "{ id: $.id, sum: $$.Sum('$.val') }", "$.id")
.ToArray();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
Here is another option, introducing an Array.prototype.sum helper:
Array.prototype.sum = function (init = 0, fn = obj => obj) {
if (typeof init === 'function') {
fn = init;
init = 0;
}
return this.reduce(
(acc, ...fnArgs) => acc + fn(...fnArgs),
init
);
};
// .sum usage examples
console.log(
// sum simple values
[1, 2, 3].sum(),
// sum simple values with initial value
[1, 2, 3].sum(10),
// sum objects
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(obj => obj.a),
// sum objects with initial value
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(10, obj => obj.a),
// sum custom combinations
[{ amount: 1, price: 2 }, { amount: 3, price: 4 }]
.sum(product => product.amount * product.price)
);
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }];
// solutions
console.log(
array.filter(obj => obj.id === 1).sum(obj => obj.val),
array.filter(({id}) => id === 1).sum(({val}) => val),
array.sum(({id, val}) => id === 1 ? val : 0)
);
references:
Array.prototype.reduce
Array.prototype.filter
Arrow functions used in sum(obj => obj.val)
Object destructing assignment used in ({id}) => id === 1
Rest parameters used in (acc, ...fnArgs) => acc + fn(...fnArgs)
Conditional (ternary) operator used in id === 1 ? val : 0

Categories