Sum values inside of array with javascript - javascript

I'm getting info from an api, and what I want to do is sum the values inside of it. Let's say that the next code:
function totalPesos(){
$http.get('/api/valueForTest')
.then(function(data){
$scope.resumePesos = data.data.Response;
//console.log($scope.resumePesos);
}
Get the next answer:
[{Id: 60, Name: Chuck, Quantity: 300},
{Id: 61, Name: Arthur, Quantity: 199},
{Id: 62, Name: John, Quantity: 450}]
What I want to do is sum the Quantity. How can I do that? I've tried with:
$scope.resumePesos.reduce(function(a,b){return a + b; });
But the answer was [object Object]

Try the following with pure JS:
var data = [{Id: 60, Name: 'Chuck', Quantity: 300},
{Id: 61, Name: 'Arthur', Quantity: 199},
{Id: 62, Name: 'John', Quantity: 450}]
var sum = data.reduce(function(a, b){
a += b['Quantity'];
return a;
},0)
console.log(sum);

I would write it like this:
$scope.resumePesos.reduce((acc, x) => acc + x.Quantity, 0);
Remember that the 1st argument to the function passed to reduce is the accumulator, and the 2nd is each value you are iterating over, which in this case will be each object. Therefore you need to access the Quantity property of each object. Then you need to pass the initial value of the accumulator as the 2nd argument to reduce itself. Which in this case will be 0, since we want just a number as the result

You should try this instead:
$scope.resumePesos.reduce((a,b) => {return a + b.Quantity}, 0); // Note: 0 at the end

You are doing two things wrong - you haven't set an initial value to the reduce function and you are summing object instead of its numerical property (.Quantity).
var sum = $scope.resumePesos.reduce(function(acummulated, rp) {
return accumulated + rp.Quantity;
}, 0);

Just Use
$scope.sum = $scope.resumePesos.reduce(function(a,b){return a + b.Quantity; }, 0);

You can use lodash and it will be useful if you want some other functions on lodash.
You can do
_.sumBy($scope.resumePesos, 'Quantity');
var data = [
{Id: 60, Name: 'Chuck', Quantity: 300},
{Id: 61, Name: 'Arthur', Quantity: 199},
{Id: 62, Name: 'John', Quantity: 450}
]
console.log(_.sumBy(data, 'Quantity'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Thanx to all, i've tried with all your comments, and worked fine!

Related

Summing Records and Consolidating Based on IDs in Array

I have an array of records that contain objects, each with an id and an amount. Now, in this array, some elements have the same id. What I need to do is iterate over this array, and first, sum up the values for records that have the same id, and then return just one record when that is the case - so I end up with an array with only unique ids -- each one also containing an amount property.
In other words, I want to take this array:
const records = [
{id: 1, amount: 10},
{id: 1, amount: 20},
{id: 2, amount: 10},
{id: 3, amount: 10},
{id: 3, amount: -10}
];
... and produce this array:
const transformedRecords = [
{id: 1, amount: 30},
{id: 2, amount: 10},
{id: 3, amount: 0}
];
I've thought about using a for-of loop for this, but that might bet pretty verbose, and I'm guessing there's a more succinct way to accomplish this - perhaps with reduce()? What's an elegant way to approach this, preferably using es6+ syntax?
Use Array.reduce, for each iteration, check if you have an object with the current id in the accumulator, if you do, add the amounts, if not, push the current object to the accumulator :
const records = [
{id: 1, amount: 10},
{id: 1, amount: 20},
{id: 2, amount: 10},
{id: 3, amount: 10},
{id: 3, amount: -10},
{id: 4, amount: -10},
{id: 4, amount: -10}
];
const result = records.reduce((acc, curr) => {
const ndx = acc.findIndex(e => e.id === curr.id);
if(ndx > -1) {
acc[ndx].amount += curr.amount
}
else{
acc.push(curr)
}
return acc;
}, [])
console.log(result)
You can use reduce() to create an object and then use map() on its entries to create array of objects back
const records = [
{id: 1, amount: 10},
{id: 1, amount: 20},
{id: 2, amount: 10},
{id: 3, amount: 10},
{id: 3, amount: -10}
];
const res = Object.entries(records.reduce((ac, a) => {
ac[a.id] = (a[a.id] || 0) + a.amount;
return ac
}, {})).map(([id, amount]) => ({id, amount: amount < 0 ? 0 : amount}))
console.log(res)

Javascript create array from existing split on property value

I'm trying to iterate over an existing array with of objects with a 'quantity' property and rebuild it by a control value.
let cart = [{id: 1, name: 'Pizza', quantity: 5, specialId: 0},
{id: 2, name: 'Burger', quantity: 2, specialId: 0}];
I have a control of 3 items i.e. for every 3 items you get a discount so I'd like to reconstitute the cart array as follows:
cart = [{id: 1, name: 'Pizza', quantity: 3, specialId: 1},
{id: 2, name: 'Pizza', quantity: 2, specialId: 2},
{id: 3, name: 'Burger', quantity: 1, specialId: 2},
{id: 4, name: 'Burger', qty: 1, specialId: 0}]
I've looked at several ways of doing this mostly around creating a new array of single quantity items and then creating another final array but surely that isn't very efficient?
I'd appreciate any pointers. I have a horrible feeling I'm missing something simple and have stared at this too long.
If I understand correctly the amount of three is ignorant of the type of product, so the second batch of three (in your example) consists of 2 pizzas and 1 burger.
The specialId seems to be unique and non-zero for every complete set of three (where every item in that set shares that specialId value), and zero for any remaining item(s).
Finally, it seems that the id in the result is unrelated to the input, but just an incremental number.
Here is how you could do that:
function splitBy(cart, size) {
const result = [];
let quantity = 0;
let grab = size;
let specialId = 1;
let id = 1;
for (let item of cart) {
for (quantity = item.quantity; quantity >= grab; quantity -= grab, grab = size, specialId++) {
if (result.length && !result[result.length-1].specialId) result[result.length-1].specialId = specialId;
result.push(Object.assign({}, item, {quantity: grab, specialId, id: id++}));
}
if (quantity) result.push(Object.assign({}, item, {quantity, specialId: 0, id: id++}));
grab = size - quantity;
}
return result;
}
const cart = [{id: 1, name: 'Pizza', quantity: 5, specialId: 0},
{id: 2, name: 'Burger', quantity: 2, specialId: 0}];
const result = splitBy(cart, 3)
console.log(result);
Basically you have two options.
loop over the current cart, and if the quantity is over 3, split it to two, and push them both.
split the array, and then merge it together.
My guess is to go with the first option, doing something like this:
var cart = [{id: 1, name: 'Pizza', quantity: 5, specialId: 0},
{id: 2, name: 'Burger', quantity: 2, specialId: 0}];
var a = [];
cart.forEach(x => {
if (x.quantity > 3) {
let temp = {...x};
temp.quantity = 3;
a.push(temp);
x.quantity -= 3;
}
a.push(x)
});

How to add value of similar objects keys in es6

Like this is my array of objects:
var x = [
{_id: 1, total: 25},
{_id: 1, total: 22},
{_id: 2, total: 4},
{_id: 2, total: 32},
{_id: 3, total: 56},
{_id: 4, total: 21},
{_id: 4, total: 58},
]
Now I want to achieve all total sum of similar object keys like this
[
{_id: 1, total: 47},
{_id: 2, total: 36},
{_id: 3, total: 25},
{_id: 4, total: 79},
]
Can anyone suggest how to do this on es6
Use reduce. reduce is an array method that can transform an array into something else, i.e. another array that can have different length. map will always return an array with the same number of elements. And filter can return an array that has less elements but the elements will be unchanged.
Reduce gives you the more flexible behavior. You can change the elements and you can store them in whatever way you like.
const result = x.reduce((acc, el) => {
const index = acc.findIndex(({_id}) => el._id === _id);
if (index > -1) {
acc[index].total += el.total;
} else {
acc.push({...el});
}
return acc;
}, [])
console.log(result);
In case if this code would run often and on large arrays, you can use more performant but a little more complex solution where we use a hash table to store the data:
var x = [
{_id: 1, total: 25},
{_id: 1, total: 22},
{_id: 2, total: 4},
{_id: 2, total: 32},
{_id: 3, total: 56},
{_id: 4, total: 21},
{_id: 4, total: 58},
]
const temp = {};
for (const el of x) {
temp[el._id] = (temp[el._id] || 0) + el.total;
}
const result = Object.entries(temp).map(([_id, total]) => ({_id, total}));
console.log(result);
But before starting optimizing you should always check if it's worth doing by running perf tools.

JavaScript filter array function

I've made a list of ships that it represented like so:
var fleet =
["RMS MARY", 2000, 15],
["TITANIC 2", 10000, 13],
["Boaty McBoatface", 2000, 18],
["Jutlandia", 1945, 10],
["Hjejlen", 250, 8]
];
I want to write a function that will filter the ships by a given capacity.
Example:
filterByCapacity(fleet,5000)
This should only return the ship Titanic 2 since it is the only ship with a capacity higher than 5000.
Any ideas on how to write such a function?
Easy :
function filterByCapacity(fleet, capacity) {
var filteredArray = [];
for (var i = 0; i < fleet.length; i++) {
// Supposing we know that the capacity is the second index in the array
if (fleet[i][1] >= capacity) // Or you can make this strictly greather than (>)
filteredArray.push(fleet[i]);
}
return (filteredArray);
}
But I suggest you use objects rather than arrays. Something more like this :
var fleet = [
{
name: "RMS MARY",
capacity: 2000,
age: 15, // I had no idea what the third index meant so I made up one
},
{
name: "TITANIC 2",
capacity: 10000,
age: 13,
},
{
name: "Boaty McBoatface",
capacity: 2000,
age: 18,
},
{
name: "Jutlandia",
capacity: 1945,
age: 10,
},
{
name: "Hjejlen",
capacity: 250,
age: 8,
}
];
That way you can make one generic function filterBy(fleet, paramName, paramValue) that could return you the ships that match the filter
First, I'd like to point out that your array was badly made. You were missing a left square bracket on the first entry ("RMS MARY".) The corrected array is below:
var fleet = [
["RMS MARY", 2000, 15],
["TITANIC 2", 10000, 13],
["Boaty McBoatface", 2000, 18],
["Jutlandia", 1945, 10],
["Hjejlen", 250, 8],
];
Second, I'd recommend that you represent the ships with objects instead of arrays, so you'd have something like this:
var fleet = {
{name: "RMS MARY", capacity: 2000, somethingElse: 15},
{name: "TITANIC 2", capacity: 10000, somethingElse: 13},
{name: "Boaty McBoatface", capacity: 2000, somethingElse: 18},
{name: "Jutlandia", capacity: 1945, somethingElse: 10},
{name: "Hjejlen", capacity: 250, somethingElse: 8},
};
Now, as for the function you want, I'll provide two, one for the original array representation of ships, and one for the object representation:
//array representation
function filterByCapacity(fleet, capacity){
return fleet.filter(function(ship){
return ship[1] >= capacity;
});
}
//object representation
function filterByCapacity(fleet, capacity){
return fleet.filter(function(ship){
return ship.capacity >= capacity;
});
}
Hope this helps.
Represent your ships as objects:
var fleet = [
{name: "RMS Mary", capacity: 2000, whatever: 15},
...
];
Then you can use filter in a way that is readable and makes sense.
function filterByCapacity(fleetArr, minCapacity) {
return fleetArr.filter(function(ship) {
return ship.capacity > minCapacity;
});
}
console.log(filterByCapacity(fleet, 5000)) // only Titanic

Merge duplicates in JavaScript Array

I have a stupid problem that at first seems to be simple to solve, but turns out to be tricky.
I have an array of objects, each with two properties: id and value:
[
{id: 2, value: 10},
{id: 4, value: 3},
{id: 2, value: 2},
{id: 1, value: 15}
]
I want to write an algorithm that sums up the values of ones with similar id.
My end result should be a new array with only the merged objects:
[
{id: 2, value: 12},
{id: 4, value: 3},
{id: 1, value: 15}
]
I've tried the following, but it doesn't work:
var arr = [];
arr.push({id: 2, visit:10});
arr.push({id: 4, visit:3});
arr.push({id: 2, visit:2});
arr.push({id: 1, visit:15});
// Deep copy
var copy = jQuery.extend(true, [], arr);
var masterArr = [];
for (var i = 0; i < arr.length; i++) {
var objArr = [];
objArr.push(arr[i]);
for (var j = copy.length-1; j > -1; j--) {
if (arr[i].id === copy[j].id) {
var q = copy.splice(j,1);
}
}
masterArr.push(objArr);
}
My plan was to first gather all similar objects in separate arrays (objArr), sum them up and put them in an end array (masterArr). I use jquerys extend to make a deep copy (not a reference) and reverse iteration and splice to remove objects thats already been found as "duplicates".
This doesn't work! And it doesn't seem to be a very efficient mehtod to solve my problem.
How could I do this? Performance isn't top priority but rather "nice to have"!
Thanks!
You can do it like this:
// Assuming:
a = [{id: 2, value: 10}, {id: 4, value: 3}, {id: 2, value: 2}, {id: 1, value: 15}]
var b = {}, // Temporary variable;
c = []; // This will contain the result;
// Build a id:value object ( {1: 15, 2: 12, 4: 3} )
a.map(function(current){b[current.id] = (b[current.id] || 0) + current.value});
for(var key in b){ // Form that into the desired output format.
c.push({id: parseInt(key, 10), value: b[key]});
}
console.log(c);
/* [{id: 1, value: 15},
{id: 2, value: 12},
{id: 4, value: 3}] */
I'm using parseInt(key, 10), since the keys are strings, you'll probably want them converted to integers again.
// First group the data based on id and sum the values
var temp = data.reduce(function(result, current) {
result[current.id] = (result[current.id] || 0) + current.value;
return result;
}, {});
// then recreate the objects with proper id and value properties
var result = [];
for (var key in temp) {
result.push({
id: parseInt(key, 10),
value: temp[key]
});
}
console.log(result);
Output
[ { id: 1, value: 15 },
{ id: 2, value: 12 },
{ id: 4, value: 3 } ]
The quickest approach loops over the array only once using Array.prototype.filter():
var tmp = {},
result = arr.filter(function (el) {
if (tmp.hasOwnProperty(el.id)) {
tmp[el.id].visit += el.visit;
return false;
}
else {
tmp[el.id] = el;
return true;
}
});
It also reuses the objects, though this renders the original array to contain inaccurate values. If this is a problem, you can modify the example to copy each object property to a new object.

Categories

Resources