Reputation: 2827
I have an array of an object like this
[
{
'a': 10,
elements: [
{
'prop': 'foo',
'val': 10
},
{
'prop': 'bar',
'val': 25
},
{
'prop': 'test',
'val': 51
}
]
},
{
'b': 50,
elements: [
{
'prop': 'foo',
'val': 30
},
{
'prop': 'bar',
'val': 15
},
{
'prop': 'test',
'val': 60
}
]
},
]
What I need is sum the property Val
when prop
is foo
.
So, I have to search through elements and get all objects where prop
is foo
. With this objects, I should sum the val
property.
I tried to use many combinations of _.find
, _.pick
and so on, but I don't get the right result. Can someone help me?
Upvotes: 15
Views: 60164
Reputation: 1463
Disclosure: I am the author of that library
You can use _.eachDeep method from deepdash:
let sum = 0;
_.eachDeep(obj, (value, key, parent) => {
sum += (key == 'prop' && value == 'foo' && parent.val) || 0;
});
here is an example for your case
Upvotes: 1
Reputation: 150
here the solution that worked for me if anyone needs it. but my case was a bit different, I needed to find an array that matches the id.
here a flow function which is not really nesesary but it does make the code easier to read
const flow = functions => data =>
functions.reduce((value, func) => func(value), data);
const arr = [
{
'a': 10,
elements: [
{
'prop': 'foo',
'val': 10
},
{
'prop': 'bar',
'val': 25
},
{
'prop': 'test',
'val': 51
}
]
},
{
'b': 50,
elements: [
{
'prop': 'foo',
'val': 30
},
{
'prop': 'bar',
'val': 15
},
{
'prop': 'test',
'val': 60
}
]
},
]
const result= _.flow([
data => _.map(data, 'elements'), // get all elements from the array
data => _.flatten(data), // create a singler array
data => _.find(data, { val: 65 }) // find the needed value in array
// you can keep on adding logic here depending on your need
])(arr); // the inital array
if you dont want to use the flow function it can also be done like that I think I didnt test the code but it should work
const results = _.find(_.flatten(_.map(arr, 'elements')), { val: 65 });
Upvotes: 0
Reputation: 51
Here's a one liner solution to this problem:
const _ = require('lodash')
let deepFind = (JSONArray, keyPath, keyValue) => _.find(JSONArray, _.matchesProperty(keyPath, keyValue))
let JSONArray = [{a:1, b:2, c:{d: "cd"}}, {a:3, b:4, c:{d: "ef"}}, {a:3, b:4, c:[{d: "ef"}]} ]
console.log(deepFind(JSONArray, "c.d", "cd"))
// {a:1, b:2, c:{d: "cd"}}
console.log(deepFind(JSONArray, "b", 4))
//{a:3, b:4, c:{d: "ef"}}
console.log(deepFind(JSONArray, ['c', 'd'], "cd"))
//{a:1, b:2, c:{d: "cd"}}
console.log(deepFind(JSONArray, 'c[0].d' /* OR ['c', '0', 'd']*/, "ef"))
//{a:1, b:2, c:{d: "cd"}}
Upvotes: 5
Reputation: 752
I've created library that you can use: https://github.com/dominik791/obj-traverse
findAll()
method should solve your problem. The first parameter is a root object, not array, so you should create it at first:
var rootObj = {
name: 'rootObject',
elements: [
{
'a': 10,
elements: [ ... ]
},
{
'b': 50,
elements: [ ... ]
}
]
};
Then use findAll()
method:
var matchingObjects = findAll( rootObj, 'elements', { 'prop': 'foo' } );
matchingObjects
variable stores all objects with prop
equal to foo
. And at the end calculate your sum:
var sum = 0;
matchingObjects.forEach(function(obj) {
sum += obj.val;
});
Upvotes: 5
Reputation: 27976
Here's a solution that flattens the elements and then filters the result to get the required elements before summing the val property:
var result = _.chain(data)
.map('elements') // pluck all elements from data
.flatten() // flatten the elements into a single array
.filter({prop: 'foo'}) // exatract elements with a prop of 'foo'
.sumBy('val') // sum all the val properties
.value()
Chaining is a way of applying a sequence of operations to some data before returning a value. The above example uses explicit chaining but could be (maybe should be) written using implicit chaining:
var result = _(data)
.map('elements')
.flatten()
.filter({prop: 'foo'})
.sumBy('val');
Upvotes: 28
Reputation: 11859
You can loop through the data and get the sum.Try this:
var arr=[
{
'a': 10,
elements: [
{
'prop': 'foo',
'val': 10
},
{
'prop': 'bar',
'val': 25
},
{
'prop': 'test',
'val': 51
}
]
},
{
'b': 50,
elements: [
{
'prop': 'foo',
'val': 30
},
{
'prop': 'bar',
'val': 15
},
{
'prop': 'test',
'val': 60
}
]
}
];
var sum=0;
for(x in arr){
for(i in arr[x]['elements']){
if(arr[x]['elements'][i]['prop'] == 'foo'){
sum=sum+arr[x]['elements'][i]['val'];
}
}
}
console.log(sum);
USING FILTER:
var arr=[
{
'a': 10,
elements: [
{
'prop': 'foo',
'val': 10
},
{
'prop': 'bar',
'val': 25
},
{
'prop': 'test',
'val': 51
}
]
},
{
'b': 50,
elements: [
{
'prop': 'foo',
'val': 30
},
{
'prop': 'bar',
'val': 15
},
{
'prop': 'test',
'val': 60
}
]
}
];
var sum=0;
arr.filter(function (person) {
person['elements'].filter(function(data){
if (data.prop == "foo"){
sum=sum+data.val;
}
});
});
console.log(sum);
Upvotes: 0