Add/Sum multiple values of array and display using Javascript/Python - javascript

var input = [{id: 1, price: 1200, profit:60, name:'Messi'},
{id: 2, price: 600, profit:40, name:'Ronaldo'},
{id: 1, price: 100, profit:40, name:'Messi'},
{id: 1, price: 200, profit:30, name:'Messi'},
{id: 2, price: 400, profit:10, name:'Ronaldo'},
{id: 1, price: 800, profit:10, name:'Messi'}];
Expected Output:
[{id:1, name:'Messi', price:'2300', profit:'140'},
{id:2, name:'Ronaldo', price:'1000', profit:'50'},
]
Tried:
var output = { };
input.forEach(e => output[e.id] = (output[e.id] || 0) + e.price);
console.log(output);
How to make like the expected output here.

You can do it with the .reduce() method
var input = [{
id: 1,
price: 1200,
profit: 60,
name: 'Messi'
},
{
id: 2,
price: 600,
profit: 40,
name: 'Ronaldo'
},
{
id: 1,
price: 100,
profit: 40,
name: 'Messi'
},
{
id: 1,
price: 200,
profit: 30,
name: 'Messi'
},
{
id: 2,
price: 400,
profit: 10,
name: 'Ronaldo'
},
{
id: 1,
price: 800,
profit: 10,
name: 'Messi'
}
];
/* [{id:1, name:'Messi', price:'2300', profit:'140'},
{id:2, name:'Ronaldo', price:'1000', profit:'50'}] */
var result = []; //Initialize array
//array reduce
input.reduce(function(res, value) {
if (!res[value.name]) {
res[value.name] = {
id: value.id,
name: value.name,
price: 0,
profit: 0
};
result.push(res[value.name])
}
res[value.name].price += value.price; //sums price key values
res[value.name].profit += value.profit; //sums profit key values
return res; //returns response
}, {});
//output
console.log(result)

You can use Array.prototype.reduce() combined with Nullish coalescing assignment (??=)
Code:
const input = [{ id: 1, price: 1200, profit: 60, name: 'Messi' },{ id: 2, price: 600, profit: 40, name: 'Ronaldo' },{ id: 1, price: 100, profit: 40, name: 'Messi' },{ id: 1, price: 200, profit: 30, name: 'Messi' },{ id: 2, price: 400, profit: 10, name: 'Ronaldo' },{ id: 1, price: 800, profit: 10, name: 'Messi' },]
const result = input.reduce((a, c) => {
a[c.id] ??= { id: c.id, name: c.name, price: 0, profit: 0 }
a[c.id].price += c.price
a[c.id].profit += c.profit
return a
}, {})
console.log(Object.values(result))

There are two key things here.
You need to loop over the array of objects.
JavaScript provides several mechanisms for looping over arrays. You can use a traditional for statement. Or a for/of statement, or perhaps reduce as mentioned in the other answers.
You need to be able to group information by the name provided in the objects.
Objects are very useful here as they allow you to associate (read: "group") values with unique keys.
So, the general procedure is:
Initialise an object to use for storing the keys (names) and values (some more objects)
Loop over the input array. Take the name from the object and check to see if it exists as a key in the object. If it doesn't exist add it as a key, and then assign an initial object in the iteration as its value.
Update the values of that object where appropriate
Well, now you have an object of objects where what you want is an array of objects again, similar to your input. Use Object.values to return an array of the object's values (the nested objects).
Note: in your question your required output has the price and profit as strings rather than numbers so you may have to do an additional mapping operation on the array from Object.values to get that result. I've included that code at the end of the example along with some links to documentation of other code mentioned.)
In this example I'll use a for/of loop.
const input=[{id:1,price:1200,profit:60,name:"Messi"},{id:2,price:600,profit:40,name:"Ronaldo"},{id:1,price:100,profit:40,name:"Messi"},{id:1,price:200,profit:30,name:"Messi"},{id:2,price:400,profit:10,name:"Ronaldo"},{id:1,price:800,profit:10,name:"Messi"}];
// Initialise an empty object
const temp = {};
// For every object in the input array...
for (const obj of input) {
// Destructure the properties from it
const { id, price, profit, name } = obj;
// If the name doesn't exist as a key on the object
// add it, and assign an initial object to it that mirrors
// the current object in the iteration, but where the
// values of the properties that you want to increase are
// set to zero. The key is there just go to the next step
temp[name] ??= { id, name, price: 0, profit: 0 };
// Increase the price and profit values in
// the initialised object
temp[name].price += price;
temp[name].profit += profit;
}
// Finally, after the iteration, we return
// an array of those nested objects we've created
const output = Object.values(temp);
console.log(output);
// If you want to strings for those values
// you'll have to do an additional `map` to
// stringify them
const stringified = output.map(obj => {
// Use destructuring to get the profit and
// price properties, and assign everything else to `rest`
const { price, profit, ...rest } = obj;
// Return a new object by spreading out `rest`,
// and coercing the numbers to strings
return {
...rest,
price: price.toString(),
profit: profit.toString()
};
});
console.log(stringified);
Additional information
Destructuring assignment
Nullish coalescing assignment
Rest parameters
Spread syntax

Instead of computing just price, you can also compute profit and also add id and name, the result of each id being an object instead of a number. Then use Object.values() to get the final result. As has been demonstrated elsewhere Array#reduce can also be used to give us the intermediate result.
const input = [{id: 1, price: 1200, profit:60, name:'Messi'},
{id: 2, price: 600, profit:40, name:'Ronaldo'},
{id: 1, price: 100, profit:40, name:'Messi'},
{id: 1, price: 200, profit:30, name:'Messi'},
{id: 2, price: 400, profit:10, name:'Ronaldo'},
{id: 1, price: 800, profit:10, name:'Messi'}];
/*Expected Output:
[{id:1, name:'Messi', price:'2300', profit:'140'},
{id:2, name:'Ronaldo', price:'1000', profit:'50'},
]
Tried:*/
const output = { };
input.forEach(
e => output[e.id] = {
id: e.id,
name: e.name,
price:(output[e.id]?.price || 0) + e.price,
profit:(output[e.id]?.profit || 0) + e.profit
});
console.log(Object.values(output));

Give this a shot :)
var input = [{id: 1, price: 1200, profit:60, name:'Messi'},
{id: 2, price: 600, profit:40, name:'Ronaldo'},
{id: 1, price: 100, profit:40, name:'Messi'},
{id: 1, price: 200, profit:30, name:'Messi'},
{id: 2, price: 400, profit:10, name:'Ronaldo'},
{id: 1, price: 800, profit:10, name:'Messi'}];
function transform(input) {
let output = []
let lookup = {}
for (let i = 0; i < input.length; i++) {
let item = input[i]
let key = item.id
if (lookup[key]) {
lookup[key].price += item.price
lookup[key].profit += item.profit
} else {
lookup[key] = { ...item }
}
}
for (let key in lookup) {
output.push(lookup[key])
}
return output
}
console.log(transform(input))

Related

How can I access this property in my dictionary in js?

I thought I understood how to loop through a dictionary, but my loop is wrong. I try to access the name of each sub item but my code does not work.
Here is what I did:
list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
Object.keys(list).forEach((k) => { for (i in k.items) { total += i.data; } });
console.log(total);
return total;
}
Your list is an array includes 1 object and this object has two properties title and items the items here is an array of objects each one of these objects has property cost so to calculate the total cost you need to loop through items array, here is how you do it:
let list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
list[0].items.forEach(el => {
total += el.cost;
})
console.log(total)
return total;
}
calculateCost();
Your list is an Array, not an Object.
Instead of Object.keys() use Array.prototype.reduce:
const calculateCost = (arr) => arr.reduce((tot, ob) =>
ob.items.reduce((sum, item) => sum + item.cost, tot), 0);
const list = [
{
title: 'Groceries',
items: [
{id: 4, title: 'Food', cost: 10},
{id: 5, title: 'Hygiene', cost: 20},
{id: 6, title: 'Other', cost: 30}
]
}, {
title: 'Other',
items: [
{id: 8, title: 'Scuba gear', cost: 39}
],
}
];
console.log(calculateCost(list)); // 99
Expanding on #Roko's and #mmh4all's answers, the following code adds several verification statements to handle cases where a deeply nested property in your data is not what you expect it to be.
const calculateCost = (orders) => {
let listOfCosts = [];
// For each 'order' object in the 'orders' array,
// add the value of the 'cost' property of each item
// in the order to 'listOfCosts' array.
orders.forEach(order => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray(order.items)) { return; }
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat
const orderCostArr = order.items.map(item =>
isNaN(item.cost) ? 0 : parseFloat(item.cost, 10));
if (orderCostArr.length === 0) { return; }
// Concatenate 'orderCostArr' to the 'listOfCosts' array
//listOfCosts = listOfCosts.concat(orderCostArry);
// Alternate approach is to use the spread syntax (...) to
// push the items in the array returned by 'order.items.map()'
// into the 'listOfCosts' array.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
listOfCosts.push(...orderCostArr);
});
// Use the 'reduce' method on the 'listOfCosts' array
// to get the total cost.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
const totalCost = listOfCosts.reduce(
(accumulator, currentValue) => accumulator + currentValue, 0);
return totalCost;
};
const list = [
{
title: 'Groceries',
items: [
{ id: 4, title: 'Food', cost: 10 },
{ id: 3, title: 'Baked goods', cost: 20 },
{ id: 5, title: 'Hygiene', cost: 0 },
{ id: 6, title: 'Other' }
]
}, {
title: 'Gear',
items: {},
}, {
title: 'Accessories',
items: [],
}, {
title: 'Bags',
}, {
title: 'Other',
items: [
{ id: 10, title: 'Scuba gear', cost: "5" },
{ id: 8, title: 'Scuba gear', cost: "err" },
{ id: 9, title: 'Scuba gear', cost: 59 }
],
}
];
console.log(calculateCost(list)); // 94

Compare Javascript Object field with another Object field [duplicate]

This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed last year.
I have two Objects one of them has the Store Name and the other object has the Price for an item along with the Store ID on both objects. Such as;
obj1 = [
{id: 1,name: "Store1"},
{id: 2,name: "Store2"},
{id: 3,name: "Store3"}
];
obj2= [
{ id: 1, price: 100 },
{ id: 2, price: 200 },
{ id: 3, price: 300 }
];
What I want to achieve is that compare obj1 id with obj2 id if they are the same get the price and the store name from the same id. What is the best way to achieve this? I have been trying to use Array.map or filter but can't really make it work. Thank you!
You can use map & find
const obj1 = [{
id: 1,
name: "Store1"
},
{
id: 2,
name: "Store2"
},
{
id: 3,
name: "Store3"
},
{
id: 4,
name: "Store3"
}
];
const obj2 = [{
id: 1,
price: 100
},
{
id: 2,
price: 200
},
{
id: 3,
price: 300
}
];
const newData = obj1.map((item, index) => {
return {
...item,
// if the item exist in obj2 then get the price else assign empty string
price: obj2.find(elem => elem.id === item.id) ? .price || ''
}
});
console.log(newData)

order and organize array of objects

I have this array of objects and I want to organize the objects based on their units like this:
const array = [
{ unit: 5, id: 'five'},
{ unit: 200, id: 'some22'},
{ unit: 100, id: 'recall'},
{ unit: 5, id: 'some'},
];
// Result :
[
[ { unit: 5, id: 'five'}, { unit: 5, id: 'some'}, ],
[ { unit: 6, id: 'some22'} ],
[ { unit: 55, id: 'recall'} ],
]
Note: we can simply use filter method to get the array but in my case we don't know the units and we just want to order and organize them
You could use a Map:
const array = [
{ unit: 5, id: 'five'},
{ unit: 200, id: 'some22'},
{ unit: 100, id: 'recall'},
{ unit: 5, id: 'some'},
];
const unitGroups = new Map();
for (const obj of array) {
if (!unitGroups.has(obj.unit)) {
unitGroups.set(obj.unit, []);
}
unitGroups.get(obj.unit).push(obj);
}
const result = Array.from(unitGroups.values());
console.log(result);
A different approach using the build in array method reduce, just to create a one-liner. Details to the under appreciated reduce function Array.prototype.reduce
// Initial Data
const array = [
{ unit: 5, id: 'five'},
{ unit: 200, id: 'some22'},
{ unit: 100, id: 'recall'},
{ unit: 5, id: 'some'},
];
let result = array.reduce (function(last, next){
// find index of a List with matching unit
let index = last.findIndex((itemList) => itemList.some( item => item.unit == next.unit));
if(index == -1){ // if no match was found
index = last.push([]) - 1; // add an empty Array and set the index
}
last[index].push(next); // add the Entry to the selected List
return last;
}, [])
console.info(result);
btw.: I'm asuming the posted result data is incorrect, since the "units" for some22 and recall don't match with the initial data. If this assumption is wrong please clarify
Extra: just for kicks and giggles the whole thing as a real one-liner:
( Don't try this at home ;-) )
const array = [
{ unit: 5, id: 'five'},
{ unit: 200, id: 'some22'},
{ unit: 100, id: 'recall'},
{ unit: 5, id: 'some'},
];
console.info( array.reduce((p, c) => ((p.find( l => l.some(i => i.unit == c.unit)) || p[p.push([]) - 1]).push(c), p), []));

Js - removing an object array element if value is 0

I have this array object:
0:
id: "123123"
cost: 100
quantity: 2
1:
id: "112233"
cost: 100
quantity: 5
2:
id: "112233"
cost: 100
quantity: 0
3:
id: "126233"
cost: 100
quantity: 0
What I want is to scan the whole object array and delete the ones with 0 quantity value. How do I do this with javascript?
Using the function from my answer at remove objects from array by object property,
filterInPlace(array, item => item.quantity !== 0);
const filterInPlace = (array, predicate) => {
let end = 0;
for (let i = 0; i < array.length; i++) {
const obj = array[i];
if (predicate(obj)) {
array[end++] = obj;
}
}
array.length = end;
};
const arr = [
{
id: "123123",
cost: 100,
quantity: 2,
},
{
id: "112233",
cost: 100,
quantity: 5,
},
{
id: "112233",
cost: 100,
quantity: 0,
},
{
id: "126233",
cost: 100,
quantity: 0,
},
];
filterInPlace(arr, item => item.quantity !== 0);
console.log(arr);
This does modify the array in place. If you don’t need that, the Array#filter equivalent is probably better.
This is linear-time, constant space, whereas solutions based splice have a worse worst case(s). (#Hogan’s answer is also linear-time; this is the same idea as it, but with the loops merged.)
array.filter() creates new array with the filtered objects.
take a look at this:
const values = [
{id: '123123', cost: 100, quantity: 2},
{id: '112233', cost: 100, quantity: 5},
{id: '112233', cost: 100, quantity: 0},
{id: '126233', cost: 100, quantity: 0},
]
const filtered = values.filter((obj) => obj.quantity !== 0)
console.log(filtered)
// expected output: [ { id: '123123', cost: 100, quantity: 2 }, { id: '112233', cost: 100, quantity: 5 } ]
let data = [
{id: "123123",
cost: 100,
quantity: 2},
{ id: "112233",
cost: 100,
quantity: 5},
{ id: "112233",
cost: 100,
quantity: 0},
{id: "126233",
cost: 100,
quantity: 0}
];
let i =0;
while (i < data.length) {
if (data[i].quantity === 0) {
data.splice(i, 1);
} else {
++i;
}
}
console.table(data);
Just iterate over the elements of the array and check for the value of quantity and delete with splice:
let arr = [
{
id: "123123",
cost: 100,
quantity: 2,
},
{
id: "112233",
cost: 100,
quantity: 5,
},
{
id: "112233",
cost: 100,
quantity: 0
},
{
id: "126233",
cost: 100,
quantity: 0
}
];
let len = arr.length;
for( let i = 0; i < len; i++) {
if(arr[i]['quantity'] === 0){
arr.splice(i--,1);
len--;
}
}
console.log(arr);
output:
[
{ id: '123123', cost: 100, quantity: 2 },
{ id: '112233', cost: 100, quantity: 5 }
]
I usually don't recommend mutating the input itself. But since you have this requirement, Just created this utility in order to fulfil your requirement.
let data = [
{ id: '123123', cost: 100, quantity: 2 },
{ id: '112233', cost: 100, quantity: 5 },
{ id: '112232', cost: 100, quantity: 0 },
{ id: '112234', cost: 200, quantity: 0 },
{ id: '112235', cost: 400, quantity: 1 }
]
const indexesToBeRemoved = [];
data.forEach((d, index) => {
if(d.quantity === 0) indexesToBeRemoved.push(index)
})
const length = indexesToBeRemoved.length;
for(let i=length-1; i>=0; i--) {
data.splice(indexesToBeRemoved[i],1)
}
console.log(data)
One another way of fulfilling your requirement.
let data = [
{ id: '123123', cost: 100, quantity: 2 },
{ id: '112233', cost: 100, quantity: 5 },
{ id: '112232', cost: 100, quantity: 0 },
{ id: '112234', cost: 100, quantity: 0 },
{ id: '112235', cost: 100, quantity: 1 }
]
let numberOfItemsToBeRemoved = 0;
data.forEach((d, index) => {
if(d.quantity === 0) {
data.unshift(...data.splice(index, 1))
numberOfItemsToBeRemoved++;
}
})
console.log("deleted items: ", data.splice(0, numberOfItemsToBeRemoved))
console.log(data)
Hope this helps.
If you really have an array you can't delete -- most libraries that do this functionally will create a new object. If you want to "delete" items what you really have to do is move other elements down to over write the ones you no longer want.
So I would use the following steps.
Check to see if the filter item appears at all -- if it does not there is nothing to do.
If it does appear then then let n be the index of the first item to filter. next is the next item out after it.
loop (index from n to index+next < size of array)
while next is an item to filter increase next by 1
copy from next to index
--> increase next by 1 and back to start of loop
first get element indexes and then delete them
arr=[{
'id': "123123",
cost: 100,
quantity: 2
},
{
id: "112233",
cost: 100,
quantity: 5
},
{
id: "112233",
cost: 100,
quantity: 0
},
{
id: "126233",
cost: 100,
quantity: 0
}
]
index=[]
arr.forEach(x => {
if (x.quantity==0) index.push(arr.indexOf(x))
});
i=0
index.forEach(x=>{
arr.splice(x+i,1)
i--
})
console.log(arr)

Modify object values in an array of objects

I have an array of objects that looks like this:
const arr1 = [
{id: 1, name: 'Dave', tax: 123.34543}
{id: 2, name: 'John', tax: 3243.12323}
{id: 3, name: 'Tom', tax: 122.34324}
]
And I am trying to round off the tax value, so in the end the array should look like this:
[
{id: 1, name: 'Dave', tax: 123.34}
{id: 2, name: 'John', tax: 3243.12}
{id: 3, name: 'Tom', tax: 122.34}
]
I tried using the map function like so:
arr1.map(value => Math.round(value.tax * 100)/100);
but instead of getting a modified array of objects, I get an array with only the result of the Math.round which looks like this:
[ 123.34, 3243.12, 122.34]
How do I map the array of objects to get the expected result as described above.
Thanks.
You can update tax in your map function.
See implementation below.
const arr1 = [
{id: 1, name: 'Dave', tax: '123.34543'},
{id: 2, name: 'John', tax: '3243.12323'},
{id: 3, name: 'Tom', tax: '122.34324'},
];
const taxRoundedArray = arr1.map(item => {
let tax = Math.round(item.tax * 100)/100
return {
...item,
tax
}
});
console.log(taxRoundedArray);
You could map new objects with the wanted values.
const
array = [{ id: 1, name: 'Dave', tax: 123.34543 }, { id: 2, name: 'John', tax: 3243.12323 }, { id: 3, name: 'Tom', tax: 122.34324 }],
result = array.map(o => Object.assign({}, o, { tax: Math.round(o.tax * 100) / 100 }));
console.log(result);
You are very close to the correct solution, see below:
arr1.map(value => {
value.tax = Math.round(value.tax * 100)/100);
return value
});
You need to return the altered object otherwise it gets overwritten.
Hope this helps
Lloyd
Array.map processes the entry in array and return the processed value. In the attempt, you were only returning the updated tax, however, you will need to return the object. Try following
const arr1 = [{id: 1, name: 'Dave', tax: 123.34543},{id: 2, name: 'John', tax: 3243.12323},{id: 3, name: 'Tom', tax: 122.34324}];
const arr2 = arr1.map(({tax, ...rest}) => ({...rest, tax: Math.round(tax * 100)/100}));
console.log(arr2);
map over the array and return each object with a new tax value that has been turned to a floating-point number fixed to two decimal places.
const arr1 = [{"id":1,"name":"Dave","tax":"123.34543"},{"id":2,"name":"John","tax":"3243.12323"},{"id":3,"name":"Tom","tax":"122.34324"}];
const arr2 = arr1.map(obj => {
const tax = +Number.parseFloat(obj.tax).toFixed(2);
return { ...obj, tax };
})
console.log(arr2);
You can do:
const arr1 = [
{id: 1, name: 'Dave', tax: '123.34543'},
{id: 2, name: 'John', tax: '3243.12323'},
{id: 3, name: 'Tom', tax: '122.34324'}
];
const result = arr1.map(user => {
user.tax = (Math.round(+user.tax * 100) / 100);
return user;
});
console.log(result);

Categories

Resources