Sum value form array in object - javascript

I've an object:
var stuffData = {
'Fruit': [{
'Name': 'Apple',
'Price': '2'
}, {
'Name': 'Kiwi',
'Price': '4'
}],
'Sport': [{
'Name': 'Ball',
'Price': '10'
}, {
'Name': 'Bike',
'Price': '120'
}],
'Kitchen': [{
'Name': 'Knife',
'Price': '8'
}, {
'Name': 'Fork',
'Price': '7'
}]
}
Now i want to get sum from Price Column.
I thought about this
for (var key in stuffData)
{
// and for each key i have to add new array with sum of price or what?
// But how will I display this sum then?
// I haven't any idea how can I deal with this
}

Something like this should work, mapping the objects, and reducing to sum each one
var stuffData = {
'Fruit': [{
'Name': 'Apple',
'Price': '2'
}, {
'Name': 'Kiwi',
'Price': '4'
}],
'Sport': [{
'Name': 'Ball',
'Price': '10'
}, {
'Name': 'Bike',
'Price': '120'
}],
'Kitchen': [{
'Name': 'Knife',
'Price': '8'
}, {
'Name': 'Fork',
'Price': '7'
}]
}
var o = {};
Object.keys(stuffData).forEach(function(key) {
o[key] = stuffData[key].map(function(item) {
return parseInt(item.Price, 10);
}).reduce(function(a,b) {
return a + b;
});
});
document.body.innerHTML = '<pre>' + JSON.stringify(o, 0, 4) + '</pre>';
The result would be
{
Fruit: 6,
Sport: 130,
Kitchen: 15
}

Try like this
for (var key in stuffData) {
var totalSum =0;
if(stuffData[key] = 'Fruit'{
for(var i=0; i< stuffData[key].length ; i++){
totalSum+=stuffData[key].price;
}
}
if(stuffData[key] = 'Sport'{
for(var i=0; i< stuffData[key].length ; i++){
totalSum+=stuffData[key].price;
}
}
if(stuffData[key] = 'Kitchen'{
for(var i=0; i< stuffData[key].length ; i++){
totalSum+=stuffData[key].price;
}
}
console.log("TOTAL SUM",totalSum);
}

You can use Array.prototype.reduce to sum over a list.
var categorySums = {};
for(category in stuffData) {
var items = stuffData[category];
categorySums[category] = items.reduce(function (sum, item) {
return sum + parseInt(item.Price);
}, 0);
}
If you use the library lodash (or something similar, e.g. underscore or Ramda), they've got a mapValues utility that makes this simpler:
var categorySums = _.mapValues(stuffData, function(items) {
return _.sum(items.map(function (item) {
return parseInt(item.Price);
}));
});

Thank you for every answer. The best solution is below:
var sum = {};
for (var k in stuffData)
{
sum[k] = 0;
stuffData[k].forEach(function (e)
{
sum[k] += parseInt(e.price);
});
}

Related

Sort big array into smaller by value in objects

I have large array, which looks like this:
let arr = [{
'name': '1',
'val': '12'
},{
'name': '4',
'val': '52'
},
{
'name': '11',
'val': '15'
},
{
'name': '4',
'val': '33'
},
...]
I want find all objects with same name values and push them into separated arrays .
P.S. I don't know possible name values in array.
You can easily group by name to get what you need. Below is a quite general function to group any array of objects to a Map, by specified property. Then simply make it an array and you're done
function group(arr, propertyToGroupBy) {
return arr.reduce(function(a, b) {
return a.set(b[propertyToGroupBy], (a.get(b[propertyToGroupBy]) || []).concat(b));
}, new Map);
}
const map = group(arr, 'name');
console.log(Array.from(map));
<script>
let arr = [{
'name': '1',
'val': '12'
}, {
'name': '4',
'val': '52'
},
{
'name': '11',
'val': '15'
},
{
'name': '4',
'val': '33'
}
];
</script>
You can group your array based on name in an object accumulator. Then using Object.values() you can get all the values.
let arr = [{ 'name': '1', 'val': '12' },{ 'name': '4', 'val': '52' }, { 'name': '11', 'val': '15' }, { 'name': '4', 'val': '33' }],
result = Object.values(arr.reduce((r,o) => {
r[o.name] = r[o.name] || [];
r[o.name].push(o);
return r;
},{}));
console.log(result);
let arr=[{'name':'1','val':'12'},{'name':'4','val':'52'},{'name':'11','val':'15'},{'name':'4','val':'33'}];
let groups = arr.reduce((obj, el) => ({...obj, [el.name]: [...obj[el.name] || [], el] }), {});
console.log(groups);
Group with reduce and map out the output to be an array:
let arr = [{'name': '1','val': '12'},{'name': '4','val': '52'}, {'name': '11','val': '15'},{'name': '4','val': '33'}];
// group object by same name
const dataObj = arr.reduce((all, {name, val}) => {
if (!all.hasOwnProperty(name)) all[name] = [];
all[name].push({name, val});
return all;
}, {});
// map out the result into an array
const result = Object.keys(dataObj).map(k => (dataObj[k]));
console.log(result);

how can i push price into object using javascript?

Purchasedata.find(function(err, purchasedatas) {
if (err) {
return handleError(res, err);
}
var totalprice = 0;
for (var i = 0; i < purchasedatas.length; i++) {
findProduct(i, function(i, price) {
});
}
function findProduct(i, callback) {
Productpointallocation.find({
'productcode': purchasedatas[i].ItemCode
}).exec(function(err, productpointallocations) {
if (err) {
return handleError(res, err);
}
var pointMultiplier = 0;
if (!productpointallocations) {
pointMultiplier = 0;
} else if (productpointallocations.length == 0) {
pointMultiplier = 0;
}
if (pointMultiplier >= 0) {
var totalprice = (parseFloat(purchasedatas[i].ItemCost.value)) / 10 * pointMultiplier;
purchasedatas.push({price:totalprice,productname:productpointallocations[0].productname});
console.log(purchasedatas);
}
});
}
});
In purchasedata i am getting two objects
[ { _id: 592fbd65304a7315f87d3f40,
ItemCode: '10',
PurchaseQuantity: 3,
ItemCost: 15,
},
{ _id: 592fbd65304a7315f87d3f3f,
ItemCode: '6',
PurchaseQuantity: 1,
ItemCost: 5,
}]
based on ItemCode i am calculating price. after calculating price i want push price and product name into purchasedatas object
purchasedatas.push({price:totalprice,productname:productpointallocations[0].productname});
i wrote above code but i am getting object like this
[ { _id: 592fbd65304a7315f87d3f40,
ItemCode: '10',
PurchaseQuantity: 3,
ItemCost: 15,
},
{ _id: 592fbd65304a7315f87d3f3f,
ItemCode: '6',
PurchaseQuantity: 1,
ItemCost: 5,
},
{ price: 4.5, productname: ' ADAPTER-PCS' } ]
[ { _id: 592fbd65304a7315f87d3f40,
ItemCode: '10',
PurchaseQuantity: 3,
ItemCost: 15,
},
{ _id: 592fbd65304a7315f87d3f3f,
ItemCode: '6',
PurchaseQuantity: 1,
ItemCost: 5,
},
{ price: 4.5, productname: 'ADAPTER-PCS' },
{ price: 1, productname: 'UNIVERSAL AC DC ' } ]
my expectation result after pushing price and productname
[ { _id: 592fbd65304a7315f87d3f40,
ItemCode: '10',
PurchaseQuantity: 3,
ItemCost: 15,
price: 4.5,
productname: 'ADAPTER-PCS'
},
{ _id: 592fbd65304a7315f87d3f3f,
ItemCode: '6',
PurchaseQuantity: 1,
ItemCost: 5,
price: 1,
'productname: 'UNIVERSAL AC DC '
}]
Javascript's Array.push() function will append an object to an array. If you want to add attributes to elements that are in the array already, you'll have to modify the objects. To do that you'll need to find the index of the object in the array, for example by looping over it and comparing the id.
If you want to modify all the Objects inside of the array you can also use Array.map()
You don't say push since the "push" method is only for arrays, but in fact you can add it to the object, for example:
var obj = {a: 1, b:2}
obj["c"] = 3
and it will be like that:
obj = {a: 1, b: 2, c: 3}
It's not about pushing, but about "joining" 2 objects into 1 array element - not tested but "Object.assign" should do the trick.
Purchasedata.find(function(err, purchasedatas) {
if (err) {
return handleError(res, err);
}
var totalprice = 0;
for (var i = 0; i < purchasedatas.length; i++) {
findProduct(i, function(i, price) {
});
}
function findProduct(i, callback) {
Productpointallocation.find({
'productcode': purchasedatas[i].ItemCode
}).exec(function(err, productpointallocations) {
if (err) {
return handleError(res, err);
}
var pointMultiplier = 0;
if (!productpointallocations) {
pointMultiplier = 0;
} else if (productpointallocations.length == 0) {
pointMultiplier = 0;
}
if (pointMultiplier >= 0) {
var totalprice = (parseFloat(purchasedatas[i].ItemCost.value)) / 10 * pointMultiplier;
purchasedatas[i] = Object.assign({},purchasedatas[i], {price:totalprice,productname:productpointallocations[0].productname});
console.log(purchasedatas);
}
});
}
});
EDIT: it seems that there's some mongo object instead of simple key-value pairs. Try something like that:
if (pointMultiplier >= 0) {
var totalprice = (parseFloat(purchasedatas[i].ItemCost.value)) / 10 * pointMultiplier;
purchasedatas[i] = Object.assign({},JSON.parse(JSON.stringify(purchasedatas[i])), {price:totalprice,productname:productpointallocations[0].productname});
console.log(purchasedatas);
}
or
if (pointMultiplier >= 0) {
var totalprice = (parseFloat(purchasedatas[i].ItemCost.value)) / 10 * pointMultiplier;
purchasedatas[i] = Object.assign({},tojson(purchasedatas[i]), {price:totalprice,productname:productpointallocations[0].productname});
console.log(purchasedatas);
}
So here is it how I believe it would happen,
First iterate over the array (purchasedatas) then over each object inside it:
for (var i = 0; i < purchasedatas.length; i++) {
for (var key in obj) {
if(purchasedatas[i]["ItemCode"] === req.body.ItemCode) {
purchasedatas[i]["price"] = req.body.price;
purchasedatas[i]["productname"] = req.body.productname;
}
}
}
return purchasedatas;
Hope that this is what you want or at least what you are asking for.

ImmutableJS: merge two list of objects, without duplicating them

Supposing I have the below:
var allFoods = Immutable.List();
var frenchFood = Immutable.List([
{
'type': 'french fries',
'price': 3
},
{
'type': 'petit gateau',
'price': 40
},
{
'type': 'croissant',
'price': 20
},
]);
var fastFood = Immutable.List([
{
'type': 'cheeseburger',
'price': 5
},
{
'type': 'vegan burger',
'price': 20
},
{
'type': 'french fries',
'price': 3
}
]);
I want to merge both lists, in a way that I also remove dupes (in this case, french fries), so the expected result would be:
{
'type': 'french fries', // keep the first french fries
'price': 3
},
{
'type': 'petit gateau',
'price': 40
},
{
'type': 'croissant',
'price': 20
},
{
'type': 'cheeseburger',
'price': 5
},
{
'type': 'vegan burger',
'price': 20
}
What I'm trying (doesn't remove dupes):
allFoods = frenchFood.concat(fastFood);
allFoods = allFoods.filter(function(item, pos) {
return allFoods.indexOf(item) === pos;
});
Which returns arrays merged, but still duplicated.
What am I missing?
const allFoods = frenchFood.concat(fastFood.filter((item) =>
frenchFood.indexOf(item) < 0
));
I would use reduce
var result = frenchFood.concat(fastFood).reduce( (reduction, food) => {
if(reduction[food.type]) {
return reduction;
} else {
return reduction.set([food.type], food);
}
}, new Immutable.Map()).valueSeq().toList();
I would highly encourage you to not nest js objects inside immutable structures. Better to wrap those objects in an Immutable.Map() or do Immutable.fromJS(yourJsObj).
Least amount of code
const results = Immutable.Set(frenchFood).union(Immutable.Set(fastFood));
However #rooftop answer fastest
https://jsperf.com/union-vs-concat-immutable
I found a best solution (for me) on medium, link to origin answer is dead: https://medium.com/#justintulk/merging-and-deduplicating-data-arrays-with-array-reduce-efaa4d7ef7b0
const arr1 = [
{ id: 1, name: 'Array 1-1' },
{ id: 2, name: 'Array 1-2' },
{ id: 3, name: 'Array 1-3' }
]
const arr2 = [
{ id: 1, name: 'Array 2-1' },
{ id: 3, name: 'Array 2-3' },
{ id: 4, name: 'Array 2-4' }
]
const mergeArrObjectsUnique = (currentArr, newArr) => {
let obj = {}
currentArr.forEach(item => {
obj[item.id] = item
})
newArr.forEach(item => {
obj[item.id] = item
})
let result = [];
for(let p in obj) {
if(obj.hasOwnProperty(p))
result.push(obj[p])
}
console.log('result: ', result)
return result
}
mergeArrObjectsUnique(arr1, arr2)

Adding price of product records with same name in an array of objects

Well, I need to add price of products with same name and modify the array accordingly.
Input: records=[{'name':'A', 'price':200},{'name':'B', 'price':350},{'name':'A', 'price':150},{'name':'B', 'price':300}]
Output: records=[{'name':'A', 'price':350},{'name':'B', 'price':650}]
Will be glad if the solution is provided using javascript forEach function.
You could build a new array with the wanted objects and add the price to the grouped item, with a reference from this object.
var records = [{ 'name': 'A', 'price': 200 }, { 'name': 'B', 'price': 350 }, { 'name': 'A', 'price': 150 }, { 'name': 'B', 'price': 300 }],
result = [];
records.forEach(function (a) {
if (!this[a.name]) {
this[a.name] = { name: a.name, price: 0 };
result.push(this[a.name]);
}
this[a.name].price += a.price;
}, {});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Another way of doing it
records.map(function(element, index, array){
return {
name: element.name,
price: (array
.reduceRight(function(previousvalue, currentvalue, currentindex){
var dup = currentvalue.name === element.name;
var cp = dup? currentvalue.price: 0;
dup? array.splice(currentindex, 1):0;
return previousvalue + cp;
}, 0))}
}).filter(function(element){ return typeof element !== "undefined";});
Fiddle
https://jsfiddle.net/sfy2p1rf/1/

Combining array with condition in javascript

I have an array as below
arr1 = [{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Kris',
'ProjectId': '223'
}, {
'Name': 'Ken',
'ProjectId': '223'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}, {
'Name': 'Kris',
'ProjectId': '786'
}]
I want the resulting array where duplicates from array based on name is removed but if the ProjectId = 123 keep that in array and remove other duplicate
i.e in above example there are 2 duplicates with name Ken but one record has ProjectId = 123 , in that case consider this record and delete other similar name duplicate
Also , if the duplicate does not contain ProjectId as 123 remove any one duplicate.
Ex : In above example there are 2 duplicates with name Kris but don't have ProjectId as 123 in that case consider any one of the record.
i.e my resulting array should be like this
[{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Kris',
'ProjectId': '223'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}]
or
[{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}, {
'Name': 'Kris',
'ProjectId': '786'
}]
function removeDuplicatesByName(arr) {
var obj = {};
for(var i = 0; i < arr.length; i++) {
obj[arr[i].Name] = arr[i];
}
var out = [];
for(var key in obj)
out.push(obj[key]);
out.sort(function(a, b){ return a.ProjectId - b.ProjectId; });
return out;
}
This uses the fact that objects can't have duplicate keys to remove all the duplicates in your array by name. It returns them sorted by ProjectId, since the ordering will be lost when it goes into an object.
JSFIDDLE DEMO
This should work. :)
var arr1 = [{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Kris',
'ProjectId': '223'
}, {
'Name': 'Ken',
'ProjectId': '223'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}, {
'Name': 'Kris',
'ProjectId': '786'
}];
var removeDups = function (array) {
for (var i=0; i < array.length; i++) {
var obj1 = array[i];
for (var j=0; j < array.length; j++) {
if (j==i)
continue;
var obj2 = array[j];
if (obj1.Name == obj2.Name) {
var indexToDelete = checkProject123(i, j);
array.splice(indexToDelete-1, indexToDelete);
}
}
}
return array;
}
var checkProject123 = function (i, j) {
if (arr1[i].ProjectId == '123')
return j; // Index i has projectId 123 so return j to be deleted.
else if (arr1[j].ProjectId == '123')
return i; // Index j has projectId 123 so return i to be deleted.
else
return i; // Neither of them have projectId 123 so delete the first one, idk
}
console.log(removeDups(arr1));
Working solution:
var arr1 = [{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Kris',
'ProjectId': '223'
}, {
'Name': 'Ken',
'ProjectId': '223'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}, {
'Name': 'Kris',
'ProjectId': '786'
}];
function filter(arr) {
var i, j;
for (i = 0; i < arr.length; i++) {
for (j = i; j < arr.length; j++) {
if (i === j) { continue; }
if (arr[j].Name === arr[i].Name) {
var spliceIndex = (arr[j].ProjectId === '123') ? i : j;
arr.splice(spliceIndex, 1);
j--;
if (spliceIndex === i) {
i--;
break;
}
}
}
}
return arr;
}
console.log(filter(arr1));
This is one solution. You can filter your input array and search if the current element position is the same that the first result in the input array to eliminate the duplicates.
var arr1 = [{
'Name': 'Ken',
'ProjectId': '123'
}, {
'Name': 'Kris',
'ProjectId': '223'
}, {
'Name': 'Ken',
'ProjectId': '223'
}, {
'Name': 'Ben',
'ProjectId': '229'
}, {
'Name': 'Alex',
'ProjectId': '222'
}, {
'Name': 'Kris',
'ProjectId': '786'
}];
var result=arr1.filter(function(e,i,a){
if (a.map(function(d) { return d['Name']; }).indexOf(e.Name) == i) {
return e;
}
})
console.log(result);
Use lodash's uniq function. Pass in a custom comparator. Example code from their documentation:
// using an iteratee function
_.uniq([1, 2.5, 1.5, 2], function(n) {
return this.floor(n);
}, Math);
// → [1, 2.5]
Or the pluck shorthand:
// using the `_.property` callback shorthand
_.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
I believe underscore.js has the same function.

Categories

Resources