Sum of string values on array object - javascript

I need to sum some object values in an array. Some can be int while others can be string ie:
JavaScript:
let array = [
{quantity: 1, amount: "24.99"}
{quantity: 5, amount: "4.99"},
]
Digging around Stack Overflow I have found this method (Im using React):
Array.prototype.sum = function (prop) {
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
total += this[i][prop]
}
return total
};
let totalQuantity = array.sum("quantity");
console.log(totalQuantity);
While that works great, I need to do the same for the string amount. Since I need to convert amount into float, the above will not work. React complains about Component's children should not be mutated.
Not being JS ninja, I thought this would do some magic:
Array.prototype.sum = function (prop) {
var newProp = parseFloat(prop);
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
total += this[i][newProp] // Surely this is wrong :(
}
return total
};
Any clean way to achieve this?
I need this:
let totalAmount = array.sum("amount");

Define a generic sum function, which is as trivial as
let sum = a => a.reduce((x, y) => x + y);
and apply it to the list of values picked from the source array:
let array = [
{quantity: 1, amount: "24.99"},
{quantity: 5, amount: "4.99"}
];
let sum = a => a.reduce((x, y) => x + y);
let totalAmount = sum(array.map(x => Number(x.amount)));
console.log(totalAmount.toFixed(2))

Please try:
Array.prototype.sum = function (prop) {
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
total += parseFloat(this[i][prop]) // Surely this will work :)
}
return total
};

const array = [
{quantity: 1, amount: "24.99"},
{quantity: 5, amount: "4.99"}
]
Array.prototype.sum = function(key) {
return this.reduce(function(total, item) {
return total + parseFloat(item[key]);
}, 0);
}
// weird javascript math ...
console.log(array.sum("amount"));
// workaround
console.log(array.sum("amount").toFixed(2));
This work fine ;)

I usually use the reduce() method for situations like these. Here is a little demo: http://codepen.io/PiotrBerebecki/pen/zKEQgL
let array = [
{quantity: 1, amount: "24.99"},
{quantity: 5, amount: "4.99"}
]
function sumProperty(arr, type) {
return arr.reduce((total, obj) => {
if (typeof obj[type] === 'string') {
return total + Number(obj[type]);
}
return total + obj[type];
}, 0);
}
let totalAmount = ( sumProperty(array, 'amount') ).toFixed(2);
console.log( totalAmount ); // 29.98
let totalQuantity = sumProperty(array, 'quantity');
console.log( totalQuantity ); // 6

Related

JavaScript: find Object with highest summed values from Array

In need the Object with maximum a+b value from myArray
var myArray = [{a:5,b:10},{a:10,b:7},{a:8,b:5}];
Right now I have something that returns me the index:
var max = [], maxIndex;
myArray.map(x=>max.push(x.a + x.b))
maxIndex = max.indexOf( Math.max.apply(Math, max))
I need something that returns the Object and not its index, so far working with
var maxObject = myArray.map(x=>x.a + x.b).reduce((x,y)=>x>y)
returning false.
You can use reduce like below
var myArray = [{a:5,b:10},{a:10,b:7},{a:8,b:5}];
const finalResult = myArray.reduce((result, obj) => {
let sum = obj.a + obj.b;
if(result.sum < sum) {
return {sum, obj: {...obj}}
}
return result;
}, {sum: 0, obj: {}})
console.log(finalResult.obj)
Hope this helps.
No need for map as reduce will itterate over you array.
var myArray = [{a:5,b:10},{a:10,b:7},{a:8,b:5}];
var biggestSumObj = myArray.reduce((total,current)=>{
if((current.a + current.b) > (total.a + total.b)){
return current;
}
return total;
});
console.log(biggestSumObj);
fiddle: return biggest object
You may try something like that:
let myArray = [{a:5,b:10},{a:10,b:7},{a:8,b:5}];
let max = myArray[0].a + myArray[0].b;
let maxObject = {...myArray[0]};
myArray.map((obj) => {
if(max < obj.a + obj.b) {
max = obj.a + obj.b;
maxObject = {...obj}
}
});
console.log(maxObject); // { a: 10, b: 7 }
Based on your code, after you found the index of the object with the highest summed values
, you simply return the array in that index:
var myArray = [{a:5,b:10},{a:10,b:7},{a:8,b:5}];
var max = [],
maxIndex;
var result;
myArray.map(x => max.push(x.a + x.b))
maxIndex = max.indexOf(Math.max.apply(Math, max))
result = myArray[maxIndex];
console.log(result);

How to decrement items in array Incrementally based on the given quantity in Javascript

I have this sample array of objects
mangoes:[
{ quantity:5},
{ quantity:8},
{ quantity:13},
{ quantity:4}
]
When I remove x mangoes, that x should be subtracted from the first element in the array, and if that x exceed the first element then it should reduce the remained quantity in the second item in the array...and so forth.
This is to say, I need the quantity to be reduced starting from the first one in the array down to the second if it exceed, to the third etc..
For example, If I buy 2 mangoes, It should minus 2 in the first array element and the resulting mangoes array should be
mangoes:[
{ quantity:3},
{ quantity:8},
{ quantity:13},
{ quantity:4}
]
On the other hand, If I would have bought 7 mangoes, it should reduce all 5 from first array element and then remove 2 mangoes from the second element...and hence the final array would be like this below
mangoes:[
{ quantity:0},
{ quantity:6},
{ quantity:13},
{ quantity:4}
]
By Using Javascript, how can I achieve this?
WHAT I HAVE TRIED
I have tried like this below, It works only for the first element(case) when the x is less, but for other case it doesn't work;
var x = 2
var done = false
mangoes.forEach(function (item,i) {
if(mangoes[i].quantity>=x && !done){
item.quantity = mangoes[i].quantity - x
done = true
}
})
const takeMangoes = (num, from) => from.map(x => {
const take = Math.min(x.quantity, num);
num -= take;
// Original way, keep all properties, don't mutate original
//return {...x, quantity: x.quantity - take};
// Pick from below:
// New way 1, mutate original in place
x.quantity = x.quantity - take;
return x;
// New way 2, limit to OWN properties
return Object.getOwnPropertyNames(x).reduce((a, c) => {
a[c] = x[c];
if (c === 'quantity') {
a[c] -= take;
}
return a;
}, {});
}).filter(x => x.quantity > 0);
console.log(takeMangoes(2, [
{quantity: 5},
{quantity: 8},
{quantity: 13},
{quantity: 4},
]));
console.log('------------------------');
console.log(takeMangoes(7, [
{quantity: 5},
{quantity: 8},
{quantity: 13},
{quantity: 4},
]));
You can take a closure inside map and generate the desired result.
var mangoes=[ { quantity:5},{ quantity:8},{ quantity:13},{ quantity:4}];
var toReduce = 5;
var result = mangoes.map((num=>({quantity})=>(r = Math.min(quantity,num),num=num-r,({quantity:quantity-r})))(toReduce));
console.log(result);
You can achieve that with forEach this way. But I wouldn't recommend it because even if a quantity is found to be greater than the value to be deducted, it will still loop through the whole item list as you can't break out of a forEach loop
var mangoes = [
{ quantity:0},
{ quantity:6},
{ quantity:13},
{ quantity:4}
];
var x = 2
var done = false
mangoes.forEach(function (item,i) {
if(item.quantity< x){
item.quantity = 0;
x = x- item.quantity;
}else{
item.quantity = item.quantity-x;
x=0;
}
});
console.log(mangoes)
However, I would recommend using for..of..loop so that you could conditionally break out of the loop, i.e if the quantity is found to be greater than the ones to be deducted, just deduct and break out of the loop. There's no need of further iteration.
var mangoes = [
{ quantity:5},
{ quantity:6},
{ quantity:13},
{ quantity:4}
];
var x = 1
var done = false
for(let i of mangoes){
if(i.quantity >= x){
i.quantity = i.quantity -x;
x = x - i.quantity;
break;
}else{
x = x - i.quantity;
i.quantity = 0;
}
}
console.log(mangoes)
let x = 8;
const newMangoes = mangoes.map((mango) => {
if (!x) return mango;
if (x <= mango.quantity) {
newMango = {quantity: mango.quantity - x};
x = 0;
return newMango;
} else {
x = x - mango.quantity;
return {quantity: 0};
}
});
var getMangoes = function(requested){
var remaining = requested;
var supplied = 0;
for(var i = 0; i < mangoes.length() && supplied < requested; i++){
if(mangoes[i].quantity >= remaining){
mangoes[i].quantity -= remaining;
supplied += remaining;
}
else {
remaining -= mangoes[i].quantity;
supplied += mangoes[i].quantity;
}
}
return(supplied);
};
var mangoesIWant = 13;
var mangoesIGot = getMangoes(mangoesIWant);

Get array value sums based on other array key values

I have an array similar to this:
var programs_array = [
{"id":3543,"category":"1","target_revenue":1845608},
{"id":2823,"category":"1","target_revenue":1627994},
{"id":1611,"category":"1","target_revenue":1450852},
{"id":1624,"category":"1","target_revenue":25473},
{"id":4626,"category":"2","target_revenue":253048},
{"id":5792,"category":"2","target_revenue":298468},
{"id":5799,"category":"2","target_revenue":256815},
{"id":5171,"category":"2","target_revenue":239090},
{"id":4064,"category":"3","target_revenue":119048},
{"id":2322,"category":"3","target_revenue":59146},
{"id":3466,"category":"3","target_revenue":29362},
{"id":3442,"category":"3","target_revenue":149860},
{"id":1254,"category":"3","target_revenue":15600},
{"id":1685,"category":"3","target_revenue":45463}
];
I want the sum of all "target_revenue" values if "category" equals 2. Currently, I'm doing this, but I'd like to ensure I'm doing this the most efficient way.
Array.prototype.sum_cat = function (prop, cat, val) {
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
if(this[i][cat]==val){total += this[i][prop]}
}
return total
}
console.log('total 2: '+programs_array.sum_cat('target_revenue','category',2));
Here's a fiddle: https://jsfiddle.net/26v48djp/
I would use reduce, adding to the accumulator if category is 2:
const programs_array=[{"id":3543,"category":"1","target_revenue":1845608},{"id":2823,"category":"1","target_revenue":1627994},{"id":1611,"category":"1","target_revenue":1450852},{"id":1624,"category":"1","target_revenue":25473},{"id":4626,"category":"2","target_revenue":253048},{"id":5792,"category":"2","target_revenue":298468},{"id":5799,"category":"2","target_revenue":256815},{"id":5171,"category":"2","target_revenue":239090},{"id":4064,"category":"3","target_revenue":119048},{"id":2322,"category":"3","target_revenue":59146},{"id":3466,"category":"3","target_revenue":29362},{"id":3442,"category":"3","target_revenue":149860},{"id":1254,"category":"3","target_revenue":15600},{"id":1685,"category":"3","target_revenue":45463}]
const getSum = (findCat) => programs_array.reduce((a, { category, target_revenue }) => (
category === findCat
? a + target_revenue
: a
), 0);
console.log(getSum("2"));
You could chain filter with a reduce to accomplish this easily and concisely.
const sum = programs_array.filter(e => e.category === '2').reduce((acc, element) => acc + element.target_revenue);
Or if you wanted a slightly more performant, but less concise way you could do the following. But the difference for an array of this size is likely negligible.
const sum = programs_array.reduce((acc, element) => {
return element.category === '2' ? (acc + element.target_revenue) : acc;
});
You can simply achieve this using array.reduce()
let arr = [{"id":3543,"category":"1","target_revenue":1845608}, {"id":2823,"category":"1","target_revenue":1627994}, {"id":1611,"category":"1","target_revenue":1450852}, {"id":1624,"category":"1","target_revenue":25473}, {"id":4626,"category":"2","target_revenue":253048}, {"id":5792,"category":"2","target_revenue":298468}, {"id":5799,"category":"2","target_revenue":256815}, {"id":5171,"category":"2","target_revenue":239090}, {"id":4064,"category":"3","target_revenue":119048}, {"id":2322,"category":"3","target_revenue":59146}, {"id":3466,"category":"3","target_revenue":29362}, {"id":3442,"category":"3","target_revenue":149860}, {"id":1254,"category":"3","target_revenue":15600}, {"id":1685,"category":"3","target_revenue":45463} ];
function getSum(prop, val){
return arr.reduce((a,curr)=> curr.category === val ? a + curr[prop] : a,0);
}
console.log(getSum("target_revenue", "2"));
In general, a for loop is going to be the most efficient solution.
See: https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7
I would use your code with slight modifications as seen below:
Array.prototype.sum_cat = function (prop, cat, val) {
let total = 0,
_len = this.length;
for (let i = 0; i < _len; i++) {
if (this[i][cat] == val) { total += this[i][prop]; }
}
return total;
}
console.log('total 2: '+programs_array.sum_cat('target_revenue','category',2));

Calculate percentage from associative array in JS

Suppose I have an array like this:
var arr = [];
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
[india: 7, indonesia: 3, usa: 1]
I need to get an array like [india: (7/11*100), indonesia: (3/11*100), usa: (1/11*100)] , i.e., to get the percentage of each country value using a single loop in javascript. How can I achieve it ?
You can use array#reduce to sum up all values and then calculate percentages inside array#map
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
let sum = Object.keys(arr).reduce((s,k) => s += arr[k], 0);
var result = Object.keys(arr).map(k => ({[k] : (arr[k]/sum * 100).toFixed(2)}));
console.log(result);
If your objects is like this var arr = {india: 7, indonesia: 3, usa: 1};, you can do it in this way.
var arr = {india: 7, indonesia: 3, usa: 1};
var sum = 0;
//Finding the sum
for(key in arr){
sum += arr[key];
}
console.log("Sum of the object values is = " + sum);
//Finding the average
for(key in arr){
arr[key] = (arr[key]/sum)*100;
}
console.log(arr);
Loop through each key and reassigned the val like this:
var countries = [];
countries["india"] = 7;
countries["indonesia"] = 3;
countries["usa"] = 1;
for (var country in countries){
if (countries.hasOwnProperty(country)) {
countries[country] = (countries[country] / 11 * 100).toFixed(2)
}
}
console.log(countries)
[india: 7, indonesia: 3, usa: 1]is wrong, you need an object, like {india: 7, indonesia: 3, usa: 1}
So, I think you need an function to do what you need, simple:
var obj = {india: 7, indonesia: 3, usa: 1}
const getPercent = (obj) {
let sum = 0
for (key in obj) {
sum += obj[key]
}
for (key in obj) {
obj[key] = (obj[key]/sum)*100
}
return obj
}
Once you change the obj, you run getPercent(obj), then you get a return, that is what's you need.
May helpful.
So, suppose you have a valid array:
var myArray = { 'key1': 2, 'key2': 5, 'key3': 14 };
/* iterates through an associative array, calculates each percentage and
adds it to a similar associative array
The percentages are not rounded
*/
function getPercentagePerKey(myArray) {
var sum = getSum(myArray);
var arrayWithPercentages = [];
for (key in myArray) {
val = myArray[key];
percentage = (val / sum) * 100;
arrayWithPercentages.push({key, percentage});
}
return arrayWithPercentages;
}
/* returns the sum given from an 'associative' array */
function getSum(myArray) {
var sum = 0;
for (key in myArray) {
sum += myArray[key];
}
return sum;
}
percentageArray = getPercentagePerKey(myArray);
console.log(percentageArray);
0: {key: "key1", percentage: 9.523809523809524}
1: {key: "key2", percentage: 23.809523809523807}
2: {key: "key3", percentage: 66.66666666666666}
You can make getters from object properties if it is allowed:
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
var sum = 0;
var percent = function(n){
return function(){ return n/sum*100; }
}
for (var k in arr) {
sum+=arr[k];
arr[k]=percent(arr[k]);
}
console.log(arr.india());
console.log(arr.usa());
console.log(arr.indonesia());

Find object having maximum value for the `id` property in an array of objects

In my array of objects, I want to find the object with the highest value for the id property.
Here is my array:
myArray = [
{
'id': '73',
'foo': 'bar'
},
{
'id': '45',
'foo': 'bar'
},
// …
];
Generally, I use $.grep to find values in an array, like this:
var result = $.grep(myArray, function (e) {
return e.id == 73;
});
But in this case I need to provide a specific id value for the object I want to select.
The question states that he wants to find the object with the greatest id, not just the greatest id...
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var max = myArray.reduce(function(prev, current) {
if (+current.id > +prev.id) {
return current;
} else {
return prev;
}
});
// max == {'id':'73','foo':'bar'}
const students = [
{ id: 100, name: 'Abolfazl', family: 'Roshanzamir' },
{ id: 2, name: 'Andy', family: 'Madadian' },
{ id: 1500, name: 'Kouros', family: 'Shahmir' }
]
If you want to find the object with max Id :
const item = students.reduce((prev, current) => (+prev.id > +current.id) ? prev : current)
// it returns { id: 1500, name: 'Kouros', family: 'Shahmir' }
If you want to find the object with min Id :
const item = students.reduce((prev, current) => (+prev.id < +current.id) ? prev : current)
// it returns {id: 2, name: "Andy", family: "Madadian"}
If you wnat to find the max Id :
const max = Math.max.apply(null, students.map(item => item.id));
// it returns 1500
If you want to find the min Id :
const min = Math.min.apply(null, students.map(item => item.id));
// it returns 2
Use the map() method of the array. Using map you can provide a function that iterates over every element in the array. In that function, you can work out the object with the highest id. For example:
myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var maxid = 0;
myArray.map(function(obj){
if (obj.id > maxid) maxid = obj.id;
});
This will give you the max id of the objects in the array.
Then you can use grep to get the related object:
var maxObj = $.grep(myArray, function(e){ return e.id == maxid; });
Alternatively, if you just want the object with the max id, you can do this:
var maxid = 0;
var maxobj;
myArray.map(function(obj){
if (obj.id > maxid) maxobj = obj;
});
//maxobj stores the object with the max id.
var max = 0;
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}]
var maxEle = myArray.map(function(ele){ if(ele.id>max){ max=ele} });
map is a function which iterates through array elements and performs specific operation.
let id = items.reduce((maxId, item) => Math.max(maxId, item.id), 0);
or
let id = Math.max(...items.map(item => item.id).concat(0)); // concat(0) for empty array
// slimmer and sleeker ;)
let id = Math.max(...items.map(item => item.id), 0);
This way is more practical, because in the case of an empty array, it returns 0, unlike
Math.max.apply(null, [].map(item => item.id)) // -Infinity
and if you want to get "autoincrement", you can just add 1 regardless of whether the array is empty or not
// starts at 1 if our array is empty
autoincrement = items.reduce((maxId, item) => Math.max(maxId, item.id), 0) + 1;
UPD: Code with map is shorter but with reduce is faster, which is felt with large arrays
let items = Array(100000).fill()
.map((el, _, arr) => ({id: ~~(Math.random() * arr.length), name: 'Summer'}));
const n = 100;
console.time('reduce test');
for (let i = 1; i < n; ++i) {
let id = items.reduce((maxId, item) => Math.max(maxId, item.id), 0);
}
console.timeEnd('reduce test');
console.time('map test');
for (let i = 1; i < n; ++i) {
let id = Math.max(items.map(item => item.id).concat(0));
}
console.timeEnd('map test');
console.time('map spread test');
for (let i = 1; i < n; ++i) {
let id = Math.max(...items.map(item => item.id), 0);
}
console.timeEnd('map spread test');
reduce test: 163.373046875ms
map test: 1282.745849609375ms
map spread test: 242.4111328125ms
If we create an even larger array, spread map will shutdown
let items = Array(200000).fill()
.map((el, _, arr) => ({id: ~~(Math.random() * arr.length), name: 'Summer'}));
reduce test: 312.43896484375ms
map test: 2941.87109375ms
Uncaught RangeError: Maximum call stack size exceeded
at :15:32
function reduceBy(reducer, acc) {
return function(by, arr) {
return arr[arr.reduce(function(acc, v, i) {
var b = by(v);
return reducer(acc[0], b) ? [b, i] : acc;
}, acc || [by(arr[0]), 0])[1]];
};
}
var maximumBy = reduceBy(function(a,b){return a<b;});
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
console.log(maximumBy(function(x){
return parseInt(x.id,10)
}, myArray)); // {'id':'73','foo':'bar'}
a shorten version using reduce()
myArray.reduce((max, cur)=>(max.likes>cur.likes?max:cur))

Categories

Resources