I am trying to Sum of the key ‘total’ from the following object, but unable to find the way. I have tried to find it by using Object.key
const data = {
"item1": {},
"item2": {
"total": 13,
},
"item3": {},
"item4": {
"total": 12,
}
}
const count = Object.keys(data).map(item => data[item].total);
console.log(count);
This is what I have tried and in consol.log it is printing 13 and 12 but I am not able to do Sum of them. Also, I have tried the reduce method which is suggested in some of the following answers.
Use Object.keys() to loop over the keys of the object and then access the total property of each object:
var data = {
"item1": {
"total": 17
},
"item2": {
"total": 13
},
"item3": {}
};
var sum = 0;
Object.keys(data).forEach(key => sum += data[key].total || 0);
console.log(sum);
You can use Object.values()
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
and Array.prototype.reduce()
The reduce() method executes a reducer function (that you provide) on each member of the array resulting in a single output value.
const data = {
"item1": {},
"item2": {
"total": 13,
},
"item3": {},
"item4": {
"total": 12,
}
}
var sum = Object.values(data)
.filter(value => Object.keys(value).length !== 0)
.reduce((a,c) => a+c.total, 0);
console.log(sum);
Use Object.values to get all the values in your data.
Then use Array.reduce to calculate the total.
const data = {
"item1": { "total": 17 },
"item2": { "total": 13 }
}
const values = Object.values(data);
console.log("Values:", values);
const total = values.reduce((a, c) => a + c.total, 0);
console.log("Total:", total);
Of course, you don't need the intermediate variable:
const total = Object.values(data).reduce((a, c) => a + c.total, 0);
const sum = Object.keys(yourObject).map(key => yourObject[key].total).reduce((a, b) => a + b, 0);
Related
Is there a built-in Javascript function to transform a list of dictionaries:
const L =
[ { "day": "20201210", "count": "100" }
, { "day": "20201211", "count": "120" }
, { "day": "20201212", "count": "90" }
, { "day": "20201213", "count": "150" }
]
into a dictionary of lists like this:
const D =
{ "day" : [ "20201210", "20201211", "20201212", "20201213"]
, "count" : [ "100", "120", "90", "150"]
}
? If not what's the simplest way to do it in JS?
(It is a little-bit similar to matrix "transpose" operation).
Note: here it's a transpose and not a groupby like in Most efficient method to groupby on an array of objects
Assuming all objects have the same keys and your array is not empty, this will work:
let D = {};
Object.keys(L[0]).forEach(k => {
D[k] = L.map(o => o[k]);
});
There are certainly more efficient solutions but this is short and concise and not too bad in terms of efficiency.
Here's a fairly short and efficient method for general values.
L.forEach(o => {
Object.keys(o).forEach(k => {
D[k] ||= [];
D[k].push(o[k]);
});
});
const L = [{
"day": "20201210",
"count": "100"
}, {
"day": "20201211",
"count": "120"
}, {
"day": "20201212",
"count": "90"
}, {
"day": "20201213",
"count": "150"
}]
let D = {};
L.forEach(o => {
Object.keys(o).forEach(k => {
D[k] ||= [];
D[k].push(o[k]);
});
});
console.log(D);
I don't think such a function exists, at least in vanilla JavaScript.
A simple, pure vanilla and clear to understand way of doing it would be like this:
var L = [
{
"day": "20201210",
"count": "100"
},
{
"day": "20201211",
"count": "120"
},
{
"day": "20201212",
"count": "90"
},
{
"day": "20201213",
"count": "150"
}
];
var D = { };
for (var dict in L)
{
for (var key in L[dict])
{
if (D[key] == null) {
D[key] = [ ];
}
D[key].push(L[dict][key]);
}
}
This is definitely not the most concise or most optimized way of doing it, though it will work.
You can just restructure your array of dictionaries as such, and re-map it with Array.prototype.map
E.g. (The following practice requires to iterate the elements with map N * X times where N is the length of L and X is the amount of properties you'd want to have in D, ignore this if you have many properties you'd want to watch.)
But, this is the easiest readable approach that I'd want to introduce to you before the 2nd approach.
const L = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];
const D = {
'day': L.map(elem => elem['day']),
'count': L.map(elem => elem['count']),
};
console.log(D);
Another approach I'd suggest is to use Array.prototype.reduce, this is by far favored in your case as it's easily expandable by adding more properties to the initial array.
const L = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];
const D = L.reduce((acc, cv) => {
for (const propertyToGrab in acc) {
if (cv.hasOwnProperty(propertyToGrab)) {
acc[propertyToGrab].push(cv[propertyToGrab]);
}
}
return acc;
}, {
'day': [],
'count': []
});
console.log(D);
const D={day:[], count:[]};
for(const item of L){
D.day.push(item.day);
D.count.push(item.count);
}
const input = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];
// Create a variable that will store the result
let result = {};
// Loop through the input with forEach
input.forEach((element) => {
// Loop through the keys
for(let key in element) {
// Check if a key is not exist in the result
if(!result.hasOwnProperty(key)) {
// Then create an key and assign an empty array to it
result[key] = [];
}
// Push the elemnts to the array.
result[key].push(element[key]);
}
});
I have an array of objects:
var items = [
{
"id":"sugar",
"type": 'eatables'
},
{
"id":"petrol",
"type": 'utility'
},
{
"id":"apple",
"type": 'fruits'
},
{
"id":"mango",
"type": 'fruits'
},
{
"id":"book",
"type": 'education'
}
];
Now I have another array of orders with the help of which I want to sort items array:
var orders = [
{
"id":"sugar",
"order":5
},
{
"id":"book",
"order":1
}
];
Now what I am trying so far in my logic is that I am putting so many loops that it is totally creating mess.
Can anyone suggest me with a short and optimized logic for this?
One approach could be creating one dictionary which will keep the order for every element. Also, I've iterated the whole items array to store the position for the elements that are not in the orders array.
First of all, I'll declare one array which keep the whole orders, thus one array with 1..N elements.
var orderNumbers = Array.from({length: items.length}, (_, v) => v + 1);
Then I started to create the dictionary by iterating orders array and remove orders from orderNumbers.
The last step is iterating the items array and use shift method to "pop" the first element.
The final dictionary will look like
{
"sugar": 2,
"book": 3,
"petrol": 1,
"apple": 4,
"mango": 5
}
In this code I used one dictionary because its lookup has complexity of O(1).
var items = [ { "id":"sugar", "type": 'eatables' }, { "id":"petrol", "type": 'utility' }, { "id":"apple", "type": 'fruits' }, { "id":"mango", "type": 'fruits' }, { "id":"book", "type": 'education' } ], orders = [ { "id":"sugar", "order":2 }, { "id":"book", "order":3 } ], orderNumbers = Array.from({length: items.length}, (_, v) => v + 1);
var ordersDict = orders.reduce((acc, item) => {
acc[item.id] = item.order;
//remove from order numbers
let index = orderNumbers.findIndex(el => el == item.order);
orderNumbers.splice(index, 1);
return acc;
}, {});
for(let i = 0; i < items.length; i++){
if(!ordersDict.hasOwnProperty(items[i].id)){
ordersDict[items[i].id] = orderNumbers[0];
orderNumbers.shift();
}
}
//sort the array
items.sort((a,b) => ordersDict[a.id] - ordersDict[b.id]);
console.log(items);
let oorder = new Object();
orders.map(item=>{oorder[item.id]=item.order});
var new_items = [];
items.map(item=>{new_items[oorder[item.id]-1]=item});
Im facing a tricky problem in forming a JSON array.
I have a below JSON where products are duplicated,
var mainJson = [{
"product": "pen",
"quantity": 3
}, {
"product": "pen",
"quantity": 3
}, {
"product": "pencil",
"quantity": 4
}, {
"product": "pencil",
"quantity": 4
}]
now i want to remove the duplicated and i want to add Quantity field and my final output should look like below...
var finalOutput = [{
"product":"pen",
"quantity":6
},{
"product":"pencil",
"quantity":8
}]
Im able to remove the duplicate records with same product name but im not able to concatenate the quantity field at the time of elimination..
Can someone please help me to resolve this?
Thank you in advance
You may walk through your source array, using Array.prototype.reduce() and insert into resulting array item, having product value found for the first time, or add current quantity should one already exist:
const mainJson = [{"product":"pen","quantity":3},{"product":"pen","quantity":3},{"product":"pencil","quantity":4},{"product":"pencil","quantity":4}],
groupped = mainJson.reduce((res,{product,quantity}) => {
const group = res.find(item => item.product == product)
group ?
group.quantity += quantity :
res.push({product,quantity})
return res
}, [])
console.log(groupped)
.as-console-wrapper {min-height: 100%}
EDIT:
Above algorithm (having O(n²) time complexity) will perform nicely when the number of unique product items is relatively small, however for large number of product items, it is reasonable (just like #CameronDowner and #StepUp suggest) to build up a sort of hash map (first pass) with products and respective totals and transform that into array of desired format (second pass) which makes it O(n) time complexity:
const mainJson = [{"product":"pen","quantity":3},{"product":"pen","quantity":3},{"product":"pencil","quantity":4},{"product":"pencil","quantity":4}],
groupObj = mainJson.reduce((r,{product,quantity}) =>
(r[product] = (r[product]||0) + quantity, r), {}),
group = Object.keys(groupObj).map(key => ({product:key, quantity: groupObj[key]}))
console.log(group)
.as-console-wrapper {min-height: 100%}
I would do this in two stages. First I would reduce the array into an object, with the product as the key and the quantity as the value.
This handles the duplicates very well because object keys can never be duplicated.
I would then map this, using Object.entries, back to an array in the desired format. Using array destructuring can make this step very clean.
const mainJson = [
{
product: "pen",
quantity: 3
},
{
product: "pen",
quantity: 3
},
{
product: "pencil",
quantity: 4
},
{
product: "pencil",
quantity: 4
}
];
const productQuantities = mainJson.reduce((acc, curr) => {
const { product, quantity } = curr;
const currentValue = acc[product] || 0; // default to zero if not set yet
return {
...acc,
[product]: currentValue + quantity
};
}, {});
console.log(productQuantities);
const productQuantitiesArray = Object.entries(
productQuantities
).map(([product, quantity]) => ({ product, quantity }));
console.log(productQuantitiesArray);
While the reduce method is quite Javascript, if you prefer a more generic way, you can do it in two steps:
Iterate over your JSON and create a Map with no duplicated items;
Iterate over the Map and get your final JSON.
Take in mind this solution is the hard way, and it is slower than the reduce method. I will not blame you if you keep with the nicer reduce option, I just wanted to point out this more generic way! The result is the same.
Following the steps, we have:
var mainJson = [{"product": "pen","quantity": 3}, {"product": "pen","quantity": 3},
{"product": "pencil","quantity": 4}, {"product": "pencil","quantity": 4}];
// Step 1
var mapJson = new Map();
for(let item of mainJson)
{
if (mapJson.has(item.product))
mapJson.set(item.product, mapJson.get(item.product) + item.quantity);
else
mapJson.set(item.product, item.quantity);
}
// Step 2
var finalJson = [];
for(let item of mapJson)
finalJson.push({product:item[0], quantity:item[1]});
console.log(finalJson);
We can use reduce function:
const result = mainJson.reduce( (a, {product, quantity})=> {
a[product] = a[product] || {product, quantity: 0};
a[product].quantity += quantity;
return a;
},{})
An example:
var mainJson = [{
"product": "pen",
"quantity": 3
}, {
"product": "pen",
"quantity": 3
}, {
"product": "pencil",
"quantity": 4
}, {
"product": "pencil",
"quantity": 4
}];
const result = mainJson.reduce( (a, {product, quantity})=> {
a[product] = a[product] || {product, quantity: 0};
a[product].quantity += quantity;
return a;
},{})
console.log(Object.values(result));
If you are bothering about performance, then you can use the following solution.
const result = mainJson.reduce( (a, {product, quantity})=> {
a[product] = a[product] || {product, quantity: 0};
a[product].quantity += quantity;
return a;
},{})
let vals = [];
for (var key in result) {
if (result.hasOwnProperty(key) ) {
vals.push(result[key]);
}
}
console.log(vals);
You can see results at JSBench.me
This is my code I have successfully sorted and got my final result to be what I wanted. Now I want to also sort so that the object name that contains the key word "newitem" will always get sorted to the bottom.
var testgogo = {
"newitemwrewt": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
"other": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
"newitemncnc": {
"brand": {
"gdhshd": true
},
"stock": 2,
"sold": 3
},
};
finalresult = Object
.keys(testgogo)
.sort(
(a, b) =>
(testgogo[a].stock !== undefined) - (testgogo[b].stock !== undefined)
|| testgogo[a].stock - testgogo[b].stock
|| testgogo[b].sold - testgogo[a].sold )[0];
console.log(finalresult);
Thanks for any help
Javascript objects can't be ordered.
If you need that data to be in an order you should make it an array.
You could sort the entries of the object based on whether the key includes the string "newitem". Then use Object.fromEntries() to convert the sorted entries back to an object
const testgogo={newitemfgre:{brand:{gdhshd:!0},stock:2,sold:3},fruit:{brand:{grgrdgdr:!0,ggyugy:!0},stock:3,sold:2},vegetable:{brand:{htrhtr:!0},stock:1,sold:1},newitemwrewt:{brand:{gdhshd:!0},stock:2,sold:3},other:{brand:{gdhshd:!0},stock:2,sold:3},newitemncnc:{brand:{gdhshd:!0},stock:2,sold:3},snack:{brand:{htrhr:!0},stock:1,sold:4},afga:{brand:{gdhshd:!0},stock:1,sold:2},other:{brand:{gdhshd:!0},stock:2,sold:3}};
const str = "newitem";
const sortedEntries = Object.entries(testgogo)
.sort((a, b) => a[0].includes(str) - b[0].includes(str));
const output = Object.fromEntries(sortedEntries)
console.log(output)
Subtracting booleans returns a 1, -1 or 0.
true - false === 1
false - true === -1
true - true === 0
So, if a[0] has "newitem" but b[0] doesn't, the key at a[0] will be moved to the end of the entries array.
I want to return the key of the first object returned by the _.orderBy() method which sorts by a nested property.
Here is the CodePen demo. In this case, the key I want to return is "charlie".
console.clear();
const ob = {
"alpha": {
"id": 27,
"lottery": {
"id": 1,
"name": "La Primitiva",
"jackpotAmount": 500,
}
},
"bravo": {
"id": 28,
"lottery": {
"id": 1,
"name": "La Primitiva",
"jackpotAmount": 10,
}
},
"charlie": {
"id": 29,
"lottery": {
"id": 1,
"name": "La Primitiva",
"jackpotAmount": 1000,
}
},
}
const out = _.orderBy(ob, (e) => {
return e.lottery.jackpotAmount;
}, ['desc'] ); // How do I get key of first property, "charlie"?
console.log(out);
This isn't the most efficient way of getting the highest jackpotAmount. Sorting is O(n log n ). You can find the highest value in O(n) time. This is also creating a temporary copy of the list so it uses a lot of extra memory for a temporary operation. Using _.maxBy() would be more efficient.
var x = _.maxBy(ob, (e) => { return e.lottery.jackpotAmount; });
return x.id;
These functions work on lists. To get the key rather than item, you need to iterate over the keys.
var keys = Object.keys(ob);
return _.maxBy(keys, (e) => { return ob[e].lottery.jackpotAmount; });
Note that this doesn't entirely solve the efficiency issues. Depending on the javascript engine, the overhead of needing the keys array and the ob[e] lookup degrade space usage to O(n) and potentially a complexity of O(n log n).
If you're targeting a modern JS engine, you can use the Map object with a hand-written search to get constant space and linear time search.
const getMax = function (map) {
let maxValue = null;
let maxKey = null;
map.forEach((value, key) => {
if (value.lottery.jackpotAmount > maxValue) {
maxValue = value.lottery.jackpotAmount;
maxKey = key;
}
});
return maxKey;
};
Here's a Codepen demo.
Cheers