javascript how to make object inline - javascript

I have some objects with different nesting. Example:
Object1
{
data: {somePage1.php:
{0:
{function:'getPrice',
item:'0568000085',
line: 6},
1:
{function:'getCurrency',
item:'066000089'
line: 9}
},
somePage2.php:...
}
}
Object2
data: {EUR:{currency:45.0417}USD:{currency:33.0346}}
and so on. What I need is function, that will make any object inline
Wished result is:
Object1
{row1:{key1:somePage1.php, key2:0, function:'getPrice', item:'0568000085', line:6}
row2:{key1:somePage1.php, key2:1, function:'getCurrency', item:'066000089', line:9}
row3:{key1:somePage2.php, key2:0, function: ... }
row4:...
}
Object2
{
row1:{key1:EUR, currency:45.0417}
row2:{key1:USD, currency:33.0346}
}
It is clear that I need recursion, but I can't figure out the whole function, something like this:
this.row = 0;
this.inline = function(d){
var that = this;
var data = d||that.data;//data have been append to this object onload
$.each(data, function(attr, value){
$.each(data[attr], function(att, val){
if(typeof(val) === 'object' || typeof(val) === 'array'){
that.inline(data[attr][att]);
}else{
$.each(data, function(){
that.row++;
});
console.log(value);
}
});
});
console.log('======> '+that.row);
},

function convert(d) {
var r = {}, j = 0;
for (var i in d) {
r['row'+(j++)] = flatten({key1:i}, d[i], 2);
}
return r;
}
function flatten(r, d, l) {
for (var i in d) {
var c = d[i];
if (c && typeof c == 'object') {
r['key'+l] = i;
flatten(r, c, l+1);
} else {
r[i] = c;
}
}
return r;
}
This uses recursion and assumes the json is arbitrarily nested, and assigns key1, key2, etc to those keys whose value is a non-null object.
Edit: Fixed to make first key use rowX (sorry for all single letter var names)

This takes each (local) property of the object data, puts it as rowN property in rows and puts the old property name as the key property, I would not recommend incrementing the key property like in one of your examples.
var i = 0, rows = {}, data = {a: {t: 1}, b: {g: 2}, c: { z: 3}};
$.each(data,
function (prop, obj) {
rows['row' + i++] = $.extend({ key: prop}, obj);
}
);
BTW - double nested loops is not recursion. It is also not clear that you need recursion, many solutions can be solved with both recursion and imperative execution with loops. The example above does not use recursion, but rather what is likely an imperative loop.
http://en.wikipedia.org/wiki/Recursion_(computer_science)

Related

Compare n objects in array

I want to compare an unlimited amount of objects in an array, like
{ a: true, b: false, c: "foo"}
and
{ a: false, b: false, c: "foo"}
and get a result like
[b,c]
This can be done with just two objects like this:
function compare(first, second) {
var shared = []
$.each(first, function(index, value){
if(second[index] == value){
shared.push(index)
}
})
return shared
}
So my question is: How to write a (recursive) function that compares n objects and returns the properties they all have in common.
Thank you for reading this
That's pretty simple if written literally:
function allCommonProperties(objects) {
if (!objects.length) return [];
var first = objects[0];
return Object.keys(first).filter(function(p) {
return objects.every(function(o) {
return first[p] === o[p];
});
});
});
No need for recursion, no need for jQuery.
An alternative approach using .filter and .every. No libs.
Object.keys(first)
.filter(function(key){
return objects.every(function(obj){
return obj[key] === first[key];
});
});
For ES6 envs
Object.keys(first).filter(key => objects.every(obj => obj[key] === first[key]));
Where
objects - an array of all objects to compare
first = objects.shift() - the first element
This solution features Array.prototype.filter in combination with Object.keys.
var setA = { a: true, b: false, c: "foo" },
setB = { a: false, b: false, c: "foo" },
commonProperties = Object.keys(setA).filter(function (k) {
return setA[k] === setB[k];
});
document.write('<pre>' + JSON.stringify(commonProperties, 0, 4) + '</pre>');
I'd do it with .reduce(), going through the array and accumulating an object containing only properties that have been found (with matching values) in all the objects so far.
I'll give my example with an "extend" function; if you're working with jQuery you could use $.extend() or you can write a simple one. The idea is to do a shallow copy of properties from one object into another, which'll be necessary for the first object in the list.
var objects = [ ... ]; // the array of objects
var resultObject = objects.reduce(function(result, obj) {
if (result === null)
result = extend({}, obj);
else {
Object.keys(result).forEach(function(key) {
if (!(key in obj) || obj[key] !== result[key])
delete result[key];
});
}
return result;
}, null);
var resultProperties = Object.keys(resultObject);
Here's what extend() might look like:
function extend(obj) {
var args = arguments;
for (var i = 1; i < args.length; ++i)
Object.keys(args[i]).forEach(function(key) {
obj[key] = args[i][key];
});
return obj;
}
I think that work:
function compareObj(obj1,obj2){
var ar =[];//you need an array to put the diffirent property
for(key in obj1){//getting all proo
try{
if (obj1[key]!=obj2[key]) //if there is diffirence
{
ar[ar.length-1]=key;
//key is the name of property
}
}
catch(err){
console.log("Not the same type of objects");
return false;
}
}
return ar ;
}
This tries to iterate as least as possible. It mutates an array that holds the keys of the initial object every time a property is no longer found on the next object and will also stop iterating the rest of the array elements if there's no common properties left.
function filterByPropertyValue(arr) {
var acc = {},
initial, objectProperties;
if (arr.length > 0) {
initial = arr[1];
objectProperties = Object.keys(initial);
for (var i = 1; i < arr.length; i++) {
if (objectProperties.length > 0) {
objectProperties.forEach(function(prop, index) {
if (initial[prop] === arr[i][prop]) {
acc[prop] = initial[prop];
} else {
delete acc[prop];
delete objectProperties[index];
}
});
} else {
break;
}
}
}
return acc;
}
var arr = [{ a: true, b: false, c: "foo"}, { a: false, b: false, c: "foo"}, { a: true, b: false, c: "bar"}];
document.getElementById('results').innerHTML = JSON.stringify(filterByPropertyValue(arr), null, '\t');
<pre id="results"></pre>

Keeping only certain properties in a JavaScript object

I have an object. I would like to modify the object (not clone it) by removing all properties except for certain specific properties. For instance, if I started with this object:
var myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
//....
p99:{p99_1:'sadf',p99_2:234},
p100:3434
}
and only want properties p1, p2, and p100, how can I obtain this object:
var myObj={
p1:123,
p2:321,
p100:3434
}
I understand how I could do this with brute force, but would like a more elegant solution.
This was the first hit when googling 'js keep only certain keys' so might be worth an update.
The most 'elegant' solution might just be using underscore.js
_.pick(myObj, 'p1', 'p2', 'p100')
Just re-initialise the object:
myObj = {
p1: myObj.p1,
p2: myObj.p2,
p100: myObj.p100
};
Another way is to delete certain properties, which is less effective:
var prop = ['p1', 'p2', 'p100'];
for (var k in myObj) {
if (prop.indexOf(k) < 0) {
delete myObj[k];
}
}
You could use this approach:
let result = (({ p1, p2, p100 }) => ({ p1, p2, p100 }))(myObj);
which I learned at https://stackoverflow.com/a/25554551/470749.
You could use delete:
for (var k in myObj) {
if (k !== 'p1' && k !== 'p2' && k !== 'p100') {
delete myObj[k];
}
}
An alternative to indexOf:
var take = /^p(1|2|100)$/;
for (var k in myObj) {
if (!take.test(k)) {
delete myObj[k];
}
}
Shorter:
var take = /^p(1|2|100)$/;
for (var k in myObj) {
take.test(k) || delete myObj[k];
}
Array to RegExp:
var take = [1, 2, 100];
take = new RegExp('^p(' + take.join('|') + ')$'); // /^p(1|2|100)$/
take.test('p1'); // true
take.test('p3'); // false
Useful in a function:
function take(o, ids) {
var take = new RegExp('^p(' + ids.join('|') + ')$');
for (var k in o) take.test(k) || delete o[k];
return o;
}
Usage:
take(myObj, [1, 2, 100]); // { p1: 123, p2: 321, p100: 3434 }
If you don't like regular expressions:
function take(o, keys) {
for (var k in o) contains(keys, k) || delete o[k];
return o;
}
function contains(array, value) {
var i = -1, l = array.length;
while (++i < l) if (array[i] === value) return true;
return false;
}
function prefix(array, prefix) {
var i = -1, l = array.length, output = [];
while (++i < l) output.push(prefix + array[i]);
return output;
}
Usage:
take(myObj, ['p1', 'p2', 'p100']);
// with a middleman :
var idsToTake = [1, 2, 100];
take(myObj, prefix(idsToTake, 'p'));
Lodash has a function called pick which does what you're describing. I know that including a library isn't ideal, but you can also cherry-pick functions when using bundles, etc.
var myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
//....
p99:{p99_1:'sadf',p99_2:234},
p100:3434
}
var newObj = _.pick(myObj, 'p1', 'p2', 'p100')
var myObj = {a: 1, b: 2, c:3};
function keepProps(obj, keep) {
for (var prop in obj) {
if (keep.indexOf( prop ) == -1) {
delete obj[prop];
}
}
}
keepProps(myObj, ['a', 'b']);
console.log(myObj);
http://jsfiddle.net/mendesjuan/d8Sp3/2/
An object stored in a variable named o :
var o = { a: 1, b: 2 };
A new reference to this object :
var p = o;
o and p both refer to the same object :
o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
o === p // true
Let's update the object through o :
delete o.b;
o // { a: 1 }
p // { a: 1 }
Let's update the object through p :
p.b = 2;
o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
As you can see, o and p are in sync.
Let's "reinitialize" o :
o = { a: o.a };
o and p now refer to different objects :
o // { a: 1 }
p // { a: 1, b: 2 }
o === p // false
Let's update the object stored in o :
o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }
Let's update the object stored in p :
delete p.a;
o // { a: 1, c: 3 }
p // { b: 2 }
As you can see, o and p are not in sync anymore.
The question is : do you want to keep both variables (o and p) synchronized? If so, the second code block of VisioN's answer is the right one, otherwise, choose the first code block.
You can code your own implementation of _.pick, and use it according to your needs.
Having this snippet of code as the base for the following cases:
const myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
//....
p99:{p99_1:'sadf',p99_2:234},
p100:3434
}
let properties= ['p1','p2', 'p3', 'p100'];
case 1:
You want a shallow copy (with references to vector values)
const myNewObj = properties.reduce((newObj,property)=>{newObj[property] = myObj[property]; return newObj}, {})
// if we modify the original vector value of 'p3' in `myObj` we will modify the copy as well:
myObj.p3.p3_1 = 99999999999;
console.log(myNewObj); // { p1: 123,​​​​​​​​​​ p2: 321,​​​​​​​​​​ p3: { p3_1: 99999999999, p3_2: 42 },​​​​​​​​​​ p100: 3434 }​​​​​
case 2:
You want a deep copy (losing references to vector values)
You can just use JSON utilities to that matter.
const myNewObj2 = properties.reduce((newObj,property)=>{newObj[property] = JSON.parse(JSON.stringify(myObj[property])); return newObj},{})
// no matter how hard you modify the original object, you will create a new independent object
myObj.p3.p3_1 = 99999999999;
console.log(myNewObj2) // { p1: 123, p2: 321, p3: { p3_1: 1231, p3_2: 342 }, p100: 3434 }​​​​​
Reusing case 2 with a function
You could implement a reducer to use it in different scenarios, like this one:
function reduceSelectedProps(origin, properties){
return (newObj,property)=>{
newObj[property] = JSON.parse(JSON.stringify(origin[property]));
return newObj
}
}
So you could have a more elegant reuse of it:
const myNewObj3 = properties.reduce(reduceSelectedProps(myObj, properties),{});
// no matter how hard you modify the original object, you will create a new independent object
myObj.p3.p3_1 = 99999999999;
console.log(myNewObj3) // { p1: 123, p2: 321, p3: { p3_1: 1231, p3_2: 342 }, p100: 3434 }​​​​​
disclaimers:
This is only an example that does not handle Date, Set, Map or function values inside the properties. To deal with all these cases (and many others), it needs a really complex function with checks on the prototypes and all that stuff. At this point, consider reusing the work of other developers using any library that could do it. Lodash?
I suppose you could add a new method to the prototype:
if (!('keepOnlyTheseProps' in Object.prototype)) {
Object.prototype.keepOnlyTheseProps = function (arr) {
var keys = Object.keys(this);
for (var i = 0, l = keys.length; i < l; i++) {
if (arr.indexOf(keys[i]) < 0) delete this[keys[i]];
}
}
}
myObj.keepOnlyTheseProps(['p1', 'p2', 'p100']);
Fiddle.
Pass a map of whitelisted keys into an IIFE (immediately invoked function expression); not just elegant but also flexible IMO (especially if moved off into a function not unlike in Juan Mendes' answer)
var myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
//....
p99:{p99_1:'sadf',p99_2:234},
p100:3434
}
var myObj = (function(origObj, whiteListMap) {
for (var prop in origObj) {
if (!whiteListMap[prop]) {
delete origObj[prop];
}
}
return myObj;
})(myObj, {'p1': 1, 'p2': 1, 'p100': 1});
console.log(JSON.stringify(myObj)); //{"p1":123,"p2":321,"p100":3434}
You could create a view on your first object, some kind of proxy that would only keep the desired properties on sight.
For instance the following function will create a view that allows to both read and write the underlying object, keeping only the choosen properties.
You can make it readonly very easily, by just removing the setter.
You might also want to seal the proxy object, so that no later modification can me made to it.
function createView(obj, propList) {
var proxy = {};
for (var propIndex in propList) {
var prop=propList[propIndex];
Object.defineProperty(proxy, prop,
{ enumerable : true ,
get : getter.bind(obj,prop),
set : setter.bind(obj,prop) } );
}
return proxy;
}
function getter(prop) { return this[prop] ; }
function setter(prop, value) { return this[prop] = value ; }
An example of use would be :
var myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
p99:{p99_1:'sadf',p99_2:234},
p100:3434
};
var objView = createView(myObj, ['p1', 'p2', 'p100']);
Here, objView 'reflects' the desired properties of myObj.
You can look at the small jsbin i made here :
http://jsbin.com/munudewa/1/edit?js,console
results :
"on objView, p1:123 p2:321 p100:3434 and p4 (not in view) is : undefined"
"modifiying, on the view, p1 to 1000 and p2 to hello "
"on objView, p1:1000 p2:hello p100:3434 and p4 (not in view) is : undefined"
"modifiying, on the viewed object, p1 to 200 and p2 to bye "
"on objView, p1:200 p2:bye p100:3434 and p4 (not in view) is : undefined"
notice that :
1) you can overwrite an object by its view, only keeping desired properties.
2) you can save in a hidden property / in a closure, the original object, so you can later change the properties you expose.
I Made this short solution for case where I have an array with objects.
so consider the array below?
arr=[{"a1":"A1","b1":"B1"},{"a1":"Z1","b1":"X1"}];
console.log(arr);
I want to keep only "b1" properties of all objects.
You can use map() and delete for that as follows:
arr=[{"a1":"A1","b1":"B1"},{"a1":"Z1","b1":"X1"}];
arr=arr.map(function(d){
delete d["a1"];
return d;
});
console.log(arr);
result is an array with objects but only "b1" properties.
just a single line of pure js code
var myObj={
p1:123,
p2:321,
p3:{p3_1:1231,p3_2:342},
p4:'23423',
//....
p99:{p99_1:'sadf',p99_2:234},
p100:3434
}
Object.keys(myObj).forEach(key => { if(!["p1","p2","p100"].includes(key)) delete myObj[key]; })

Getting an Objects nested value from an array of nested properties

I have a situation where I need to zip two Objects together retaining both of the values. I can iterate through both the objects and build an array of all the keys.
var traverse = function (obj, chain) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var tempChain = [].concat(chain || []);
tempChain.push(prop);
if (typeof obj[prop] === 'object') {
traverse(obj[prop], tempChain);
}
console.log(tempChain);
}
}
};
Passing in the following:
traverse({
'a': {
'b': 'hello world',
'b1': 'hello world 1',
'c': {
'd': 'dello'
}
}
})
Will return me:
[a]
[a,b]
[a,b1]
[a,c]
[a, c, d]
So I now have an array of nested properties in an object. How can I access essentially obj[[a,c,d]]? I know I can solve the problem through eval but I can't trust the content.
eval('window.' + ['a','c','d'].join('.'));
If I can loop through that array and check to see if the property exists in both of them, then build a new object of the combined 'zipped' values.
Perhaps something like this?
function getValueAt(obj, keyPathArray) {
var emptyObj = {};
return keyPathArray.reduce(function (o, key) {
return (o || emptyObj)[key];
}, obj);
}
Then you can use it like:
var o = { a: { c: { d: 1 } } };
getValueAt(o, ['a', 'c', 'd']); //1
However it's not efficient for non-existing properties, since it will not short-circuit.
Here's another approach without using reduce:
function getValueAt(o, keyPathArray) {
var i = 0,
len = keyPathArray.length;
while (o != null && i < len) o = o[keyPathArray[i++]];
return o;
}

Merge Objects in a JavaScript Array to object

I am trying to create a single JavaScript object from an array of objects.
Some values in the object remain the same, while the numerical or float values need to be summed up to form the new single object.
How can this be achieved?
[{
'visit_date': '2013-02-02',
'house_number': '22',
'price': 12.98,
'count_value': 21.554,
'variance': -23.434343434
},
{
'visit_date': '2013-02-02',
'house_number': '22',
'price': 34.78,
'count_value': 1.34,
'variance': -23.434343434
},
{
'visit_date': '2013-02-02',
'house_number': '22',
'price': 61.41,
'count_value':1.94,
'variance': -12.977677874
}]
You can use the reduce function to achieve it
var result = a.reduce(function (acc, c) {
acc.visit_date = c.visit_date;
acc.house_number = c.house_number;
acc.price += c.price;
acc.count_value += c.count_value;
acc.variance += c.variance;
return acc;
}, {
'visit_date': '',
'house_number': '',
'price': 0,
'count_value': 0,
'variance': 0
});
The result will be
{
visit_date: "2013-02-02",
house_number: "22",
price: 109.17,
count_value: 24.834,
variance: -59.846364742
}
Loop through the array, use a for-in loop on each object, and for entries where typeof value === "number", sum them up. Presumably do something useful when they aren't numbers, but you haven't said what. :-)
Sorry, missed the jQuery tag. It can be shorter with jQuery's each:
var dest = {};
$.each(source, function(index, entry) {
$.each(entry, function(key, value) {
if (typeof value === "number") {
dest[key] = key in dest ? dest[key] + value : value;
}
else {
// do something useful with non-numbers
}
});
});
each will loop through the array elements if you give it an array, or through the properties of an object if you give it a non-array object. So in the above, the outer each loops through your array, and the inner each loops through each object's properties.
The in operator on this line:
dest[key] = key in dest ? dest[key] + value : value;
...tells us whether dest already has a key with that name: If so, we add the value to it. If not, we create a new property for that key using the value.
Original non-jQuery:
Roughly:
var dest = {};
var entry;
var index;
var key;
var value;
for (index = 0; index < source.length; ++index) {
entry = source[index];
for (key in entry) {
value = entry[key];
if (typeof value === "number") {
dest[key] = key in dest ? dest[key] + value : value;
}
else {
// do something useful with non-numbers
}
}
}
Something like this perhaps? http://jsfiddle.net/tQLy5/1/
function aToObject(a) {
var o = {}, l = a.length;
while (l--) {
for (key in a[l]) {
if (o.hasOwnProperty(key) && typeof (o[key]) === 'number') {
o[key] += a[l][key];
} else {
o[key] = a[l][key];
}
}
}
return o;
}
Just iterate over the whole array and then over the properties of the objects in array. If the property is number you add them together, otherwise you just assign the property to the new object.

How to sum the values of a JavaScript object?

I'd like to sum the values of an object.
I'm used to python where it would just be:
sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed = sum(sample.itervalues())
The following code works, but it's a lot of code:
function obj_values(object) {
var results = [];
for (var property in object)
results.push(object[property]);
return results;
}
function list_sum( list ){
return list.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
}
function object_values_sum( obj ){
return list_sum(obj_values(obj));
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = list_sum(obj_values(a));
var summed = object_values_sum(a)
Am i missing anything obvious, or is this just the way it is?
It can be as simple as that:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b, 0);
Quoting MDN:
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).
from Object.values() on MDN
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
from Array.prototype.reduce() on MDN
You can use this function like that:
sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
Note that this code uses some ECMAScript features which are not supported by some older browsers (like IE). You might need to use Babel to compile your code.
You could put it all in one function:
function sum( obj ) {
var sum = 0;
for( var el in obj ) {
if( obj.hasOwnProperty( el ) ) {
sum += parseFloat( obj[el] );
}
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );
For fun's sake here is another implementation using Object.keys() and Array.reduce() (browser support should not be a big issue anymore):
function sum(obj) {
return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };
console.log(`sum:${sum(sample)}`);
But this seems to be way slower: jsperf.com
If you're using lodash you can do something like
_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 }))
Now you can make use of reduce function and get the sum.
const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
A regular for loop is pretty concise:
var total = 0;
for (var property in object) {
total += object[property];
}
You might have to add in object.hasOwnProperty if you modified the prototype.
Honestly, given our "modern times" I'd go with a functional programming approach whenever possible, like so:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Our accumulator acc, starting with a value of 0, is accumulating all looped values of our object. This has the added benefit of not depending on any internal or external variables; it's a constant function so it won't be accidentally overwritten... win for ES2015!
Any reason you're not just using a simple for...in loop?
var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;
for (var key in sample) {
summed += sample[key];
};
http://jsfiddle.net/vZhXs/
let prices = {
"apple": 100,
"banana": 300,
"orange": 250
};
let sum = 0;
for (let price of Object.values(prices)) {
sum += price;
}
alert(sum)
I am a bit tardy to the party, however, if you require a more robust and flexible solution then here is my contribution. If you want to sum only a specific property in a nested object/array combo, as well as perform other aggregate methods, then here is a little function I have been using on a React project:
var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
//return aggregated value of a specific property within an object (or array of objects..)
if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
return;
}
obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
const validAggregates = [ 'sum', 'min', 'max', 'count' ];
aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum
//default to false (if true, only searches (n) levels deep ignoring deeply nested data)
if (shallow === true) {
shallow = 2;
} else if (isNaN(shallow) || shallow < 2) {
shallow = false;
}
if (isNaN(depth)) {
depth = 1; //how far down the rabbit hole have we travelled?
}
var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
for (var prop in obj) {
if (!obj.hasOwnProperty(prop)) {
continue;
}
var propValue = obj[prop];
var nested = (typeof propValue === 'object' || typeof propValue === 'array');
if (nested) {
//the property is an object or an array
if (prop == property && aggregate == 'count') {
value++;
}
if (shallow === false || depth < shallow) {
propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
} else {
continue; //skip this property
}
}
//aggregate the properties value based on the selected aggregation method
if ((prop == property || nested) && propValue) {
switch(aggregate) {
case 'sum':
if (!isNaN(propValue)) {
value += propValue;
}
break;
case 'min':
if ((propValue < value) || !value) {
value = propValue;
}
break;
case 'max':
if ((propValue > value) || !value) {
value = propValue;
}
break;
case 'count':
if (propValue) {
if (nested) {
value += propValue;
} else {
value++;
}
}
break;
}
}
}
return value;
}
It is recursive, non ES6, and it should work in most semi-modern browsers. You use it like this:
const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');
Parameter breakdown:
obj = either an object or an array
property = the property within the nested objects/arrays you wish to perform the aggregate method on
aggregate = the aggregate method (sum, min, max, or count)
shallow = can either be set to true/false or a numeric value
depth = should be left null or undefined (it is used to track the subsequent recursive callbacks)
Shallow can be used to enhance performance if you know that you will not need to search deeply nested data. For instance if you had the following array:
[
{
id: 1,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 2,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 3,
otherData: { ... },
valueToBeTotaled: ?
},
...
]
If you wanted to avoid looping through the otherData property since the value you are going to be aggregating is not nested that deeply, you could set shallow to true.
Use Lodash
import _ from 'Lodash';
var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
return _.sumBy(object_array, 'c')
// return => 9
I came across this solution from #jbabey while trying to solve a similar problem. With a little modification, I got it right. In my case, the object keys are numbers (489) and strings ("489"). Hence to solve this, each key is parse. The following code works:
var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
parskey = parseInt(array[key]);
sum += parskey;
};
return(sum);
A ramda one liner:
import {
compose,
sum,
values,
} from 'ramda'
export const sumValues = compose(sum, values);
Use:
const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });
We can iterate object using in keyword and can perform any arithmetic operation.
// input
const sample = {
'a': 1,
'b': 2,
'c': 3
};
// var
let sum = 0;
// object iteration
for (key in sample) {
//sum
sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);
A simple solution would be to use the for..in loop to find the sum.
function findSum(obj){
let sum = 0;
for(property in obj){
sum += obj[property];
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
console.log(findSum(sample));
function myFunction(a) { return Object.values(a).reduce((sum, cur) => sum + cur, 0); }
Sum the object key value by parse Integer. Converting string format to integer and summing the values
var obj = {
pay: 22
};
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);
function totalAmountAdjectives(obj) {
let sum = 0;
for(let el in obj) {
sum += el.length;
}
return sum;
}
console.log(totalAmountAdjectives({ a: "apple" }))
A simple and clean solution for typescrip:
const sample = { a: 1, b: 2, c: 3 };
const totalSample = Object.values(sample).reduce(
(total: number, currentElement: number) => total + currentElement
);
console.log(totalSample);
Good luck!

Categories