Getting sum from nested array objects with Lodash? - javascript

Currenly using Angular with lodash to do some additional usability but currently hitting a roadblock.
I have the following arrays:
{
"Result": [
{
"Name": "marketeerBoston",
"Label": "Week25",
"Total": 251200,
"Specific": [
{
"Label": "3",
"Value": 25,
},
{
"Label": "4",
"Value": 250,
}
]
},
{
"Name": "marketeerJersey",
"Label": "Week25",
"Total": 776090,
"Specific": [
{
"Label": "1",
"Value": 32,
},
{
"Label": "2",
"Value": 37,
}
]
},
],
}
I really need to have the Value summed up from both array objects (so I got 344).
How to achieve that with lodash?

With lodash, you can use nested _.sumBy() calls:
const data = {"Result":[{"Name":"marketeerBoston","Label":"Week25","Total":251200,"Specific":[{"Label":"3","Value":25},{"Label":"4","Value":250}]},{"Name":"marketeerJersey","Label":"Week25","Total":776090,"Specific":[{"Label":"1","Value":32},{"Label":"2","Value":37}]}]}
const result = _.sumBy(data.Result, obj => _.sumBy(obj.Specific, 'Value'))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

Related

A better way to deal with objects using many nested forEach?

I would like to know if there is a better way to deal with nested forEach when it comes to dealing with objects with properties that are nested arrays themselves.
My object (summarized):
{
...,
"tx_responses": [
{
...
"logs" : [
{
...,
"events": [
{
"type": "coin_received",
"attributes": [
{
"key": "receiver",
"value": "somesome"
},
{
"key": "amount",
"value": "somesome"
}
]
},
...
{
"type": "transfer",
"attributes": [
{
"key": "recipient",
"value": "somesome"
},
{
"key": "sender",
"value": "somesome"
},
{
"key": "amount",
"value": "somesome"
}
]
},
{
"type": "withdraw_rewards",
"attributes": [
{
"key": "amount",
"value": "somesomesomehere"
},
{
"key": "validator",
"value": "somesome"
}
]
},
...
]
}
],
...
I am essentially trying to extract all { key: 'amount', value: 'somesomesomehere' } objects in the "attributes" array of the "type" : "withdraw_rewards" object in the "events" array.
Currently this is the code I wrote to carry out my task:
getWithdrawnAmounts: async(del_addr_) => {
let withdrawnAmounts = [];
const res = await axios.get("some_url_that_uses_del_addr_");
res.data.tx_responses.forEach(txr => {
txr.logs.forEach(log => {
log.events.forEach(evnt => {
if (evnt.type == "withdraw_rewards") {
evnt.attributes.forEach(attr => {
if (attr.key == "amount") {
withdrawnAmounts.push(attr);
}
})
}
})
})
});
return withdrawnAmounts;
}
The code helps me to get what I need, but I was wondering if there is a better way to write my code so that I dont have to use so many nested .forEach methods. I was wondering if I should use .flat() or .flatMap() but I'm curious to know how would people approach this?
Thank you!
You are going to have to call some kind of iteration for each level you're going deeper.
Now, there is a more functional way to get the desired data, using flatMap and filter:
const data = { "tx_responses": [{ "logs": [{ "events": [{ "type": "coin_received", "attributes": [{ "key": "receiver", "value": "somesome" }, { "key": "amount", "value": "somesome" }]}, { "type": "transfer", "attributes": [{ "key": "recipient", "value": "somesome" }, { "key": "sender", "value": "somesome" }, { "key": "amount", "value": "somesome" }]}, { "type": "withdraw_rewards", "attributes": [{ "key": "amount", "value": "somesomesomehere" }, { "key": "validator", "value": "somesome" }]}]}]}]};
const result = data.tx_responses
.flatMap(r => r.logs
.flatMap(l => l.events.filter(e => e.type === 'withdraw_rewards')
.flatMap(e => e.attributes.filter(a => a.key === 'amount'))
)
);
console.log(result);

Filter array of specific objects

How to use filter or forEach in javascript to output only the objects whithout parentId and the objects with only the first level of parentId.
Should output objects with ids: 1681, 1682, and 1683.
Should not output objects with ids: 1685, 1686 and 1687.
array = [ {
"id": 1681,
"label": "1",
"url": "page1",
},
{
"id": 1682,
"label": "2",
"url": "page1",
},
{
"id": 1683,
"label": "a",
"url": "page1",
"parentId": 1681,
},
{
"id": 1685,
"label": "aa",
"url": "page1",
"parentId": 1683,
},
{
"id": 1686,
"label": "aaa",
"url": "page1",
"parentId": 1683,
},
{
"id": 1687,
"label": "aaaa",
"url": "page1",
"parentId": 1683,
}
]
Something like this...
array.filter(({item}) => !item.parentId ? item.id : item.parentId)
We have to save the information if we already found a parentId from inside the filter function. A handy way to do this is by using the prefix operator ++ on a counter. This way we get around an explicit, long assignment with =. Instead we make it before.
Additionally with destructuring assignment we can extract the parentId comfortably of the array items and write a really short filter:
array=[{id:1681,label:"1",url:"page1"},{id:1682,label:"2",url:"page1"},{id:1683,label:"a",url:"page1",parentId:1681},{id:1685,label:"aa",url:"page1",parentId:1683},{id:1686,label:"aaa",url:"page1",parentId:1683},{id:1687,label:"aaaa",url:"page1",parentId:1683}];
window.parentIdCount = 0;
window.filtered =
array.filter(({parentId}) => !parentId || ++parentIdCount <= 1)
console.log(filtered)
Something like this ought to work:
const result = array.filter(object => object.parentId === undefined);

Accessing nested array properties

This may be extremely simple but I've not been able to figure out how to iterate over and access the properties in the following mix (I think) of arrays and nested objects:
myFilters = {
"color_Filter": [{
"name": "BLUE",
"count": 1,
"dataId": "BLUE"
},
{
"name": "Black",
"count": 5,
"dataId": "Black"
},
{
"name": "Blue",
"count": 14,
"dataId": "Blue"
}
],
"size_Filter": [{
"name": "10",
"count": 16,
"dataId": "10"
},
{
"name": "12",
"count": 16,
"dataId": "12"
}
]
}
What would the correct looping structure be here to pull out name, count etc from the above? The desired output is to output a string from the above with color_Filter=BLUE,Black,Blue/size_Filter=10,12
I've tried a few different approaches and none of them have been successful so far.
You could map the entries of the object and create a string for each key. Get the name from the value array using map. Then join the array of strings with a /
const myFilters = {color_Filter:[{name:"BLUE",count:1,dataId:"BLUE"},{name:"Black",count:5,dataId:"Black"},{name:"Blue",count:14,dataId:"Blue"}],size_Filter:[{name:"10",count:16,dataId:"10"},{name:"12",count:16,dataId:"12"}]};
const output = Object.entries(myFilters)
.map(([k,arr]) => `${k}=${arr.map(a => a.name)}`)
.join("/")
console.log(output)

Remove json object key value using angular

I have json response and I want to remove few object key values from it and store the edited response on other part so that I can use again.
I know by using simple javascript, but I don't have any idea in angularjs.
Json response
{
"$id": "1",
"XYZ": [],
"ABC": [
{
"$id": "41",
"ID": 1,
"Order": 0,
"Delay": 0,
"Name": "abc",
"Count": "9",
"Storage": 3,
"Groups": []
}
],
"Projected": 2019
}
Now from this Json file I want to filter out
"$id": "41","ID": 1,"Order": 0,
"Delay": 0, "Groups": [], "Name": "abc"
So my new json structure will be like this which I want to store:
{
"$id": "1",
"XYZ": [],
"ABC": [
{
"Count": "9",
"Storage": 3
}
],
"Projected": 2019
}
Any method to achieve ?
You don't need some magic angular stuff. You can just use plain old JavaScript.
My apporach iterates through all the items in the ABC array and deletes all properties defined in the props array. Note, that this actively modifies the ABC array items.
const obj = {
"$id": "1",
"XYZ": [],
"ABC": [
{
"$id": "41",
"ID": 1,
"Order": 0,
"Delay": 0,
"Name": "abc",
"Count": "9",
"Storage": 3,
"Groups": []
}
],
"Projected": 2019
}
// Now from this Json file I want to filter out
const props = ["$id", "ID", "Order", "Delay", "Groups", "Name"];
props.forEach(prop => {
obj.ABC.forEach(abc => {
delete abc[prop];
});
});
console.log(obj);
An alternative to the other solutions.
If we have a variable called json.
This method is simple
let len = json.ABC.length;
for (let i=0;i<len;i++){
delete json.ABC[i].$id;
delete json.ABC[i].ID;
delete json.ABC[i].Order;
delete json.ABC[i].Delay;
delete json.ABC[i].Groups;
delete json.ABC[i].Name;
}
try this
let json = {
"$id": "1",
"XYZ": [],
"ABC": [
{
"$id": "41",
"ID": 1,
"Order": 0,
"Delay": 0,
"Name": "abc",
"Count": "9",
"Storage": 3,
"Groups": []
}
],
"Projected": 2019
};
json["ABC"] = json["ABC"].map(obj => ({
"Count": obj["Count"],
"Storage": obj["Storage"]
}));
// or dynamic way
let keepkeys = ["Storage", "Count"];
json["ABC"] = json["ABC"].map(obj => {
let newObj = {};
keepkeys.forEach(key => newObj[key] = obj[key]);
return newObj;
});
console.log(json)

Using lodash, how I can get the maximum length of nested array object

I need to take the data from below mentioned array of object which has maximum length of nested array object. As per below my request, id : 2 values has 3 objects, result will be as mentioned below.
Anyone help me using lodash or some javascript function to achieve this.
Sample Request:
[{
"id": 1,
"values": [
{
"sub": "fr",
"name": "foobar1"
},
{
"sub": "en",
"name": "foobar2"
}
]
},
{
"id": 2,
"values": [
{
"sub": "fr",
"name": "foobar3"
},
{
"sub": "en",
"name": "foobar4"
},
{
"sub": "ts",
"name": "foobar5"
},
]
}]
Expected output:
"values": [
{
"sub": "fr",
"name": "foobar3"
},
{
"sub": "en",
"name": "foobar4"
},
{
"sub": "ts",
"name": "foobar5"
},
]
}]
This can be achieved using the native javascript reduce function as follows
var source = [...];
source.reduce((max, cur) => cur.values.length > max.values.length ? cur : max, source[0])

Categories