Javascript reduce () for an object

There is a nice Array reduce() method to get a single value from an array. Example:

 [0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){ return previousValue + currentValue; }); 

What is the best way to achieve this with objects? I would like to do this:

 { a: {value:1}, b: {value:2}, c: {value:3} }.reduce(function(previous, current, index, array){ return previous.value + current.value; }); 

However, the object does not seem to have any reduce() method.

+154
javascript object arrays reduce
Apr 01 '13 at 17:53
source share
12 answers

What you really want in this case is Object.values . Here is a brief implementation of ES6 with this in mind:

 add = { a: {value:1}, b: {value:2}, c: {value:3} } total = Object.values(add).reduce((t, n) => t + n.value, 0) console.log(total) // 6 

or simply:

 add = { a: 1, b: 2, c: 3 } total = Object.values(add).reduce((t, n) => t + n) console.log(total) // 6 
+19
Aug 20 '17 at 16:54 on
source share

One option: reduce keys() :

 var o = { a: {value:1}, b: {value:2}, c: {value:3} }; Object.keys(o).reduce(function (previous, key) { return previous + o[key].value; }, 0); 

In this case, you need to specify the initial value, or the 1st round will be 'a' + 2 .

If you want to get the result as an object ( { value: ... } ), you have to initialize and return the object each time:

 Object.keys(o).reduce(function (previous, key) { previous.value += o[key].value; return previous; }, { value: 0 }); 
+269
Apr 01 '13 at 18:03
source share

ES6 Implementation: Object.entries ()

 const o = { a: {value: 1}, b: {value: 2}, c: {value: 3} }; const total = Object.entries(o).reduce(function (total, pair) { const [key, value] = pair; return total + value; }, 0); 
+48
Feb 27 '17 at 14:58
source share

First of all, you did not quite understand that reduce the previous value.

Your pseudo-code has return previous.value + current.value , so the value of previous will be a number on the next call, not on the object.

Secondly, reduce is an Array method, not an Object One, and you cannot rely on order when repeating the properties of an object (see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements /for...in , this applies to Object.keys ); so I'm not sure if applying reduce on an object makes sense.

However, if the order is not important, you can:

 Object.keys(obj).reduce(function(sum, key) { return sum + obj[key].value; }, 0); 

Or you can just map the value of the object:

 Object.keys(obj).map(function(key) { return this[key].value }, obj).reduce(function (previous, current) { return previous + current; }); 

PS in ES6 with the syntax of the thick arrow function (already in Firefox Nightly) you can shorten a bit:

 Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current); 
+18
Apr 01 '13 at 18:16
source share

Extend Object.prototype.

 Object.prototype.reduce = function( reduceCallback, initialValue ) { var obj = this, keys = Object.keys( obj ); return keys.reduce( function( prevVal, item, idx, arr ) { return reduceCallback( prevVal, item, obj[item], obj ); }, initialValue ); }; 

Usage example.

 var dataset = { key1 : 'value1', key2 : 'value2', key3 : 'value3' }; function reduceFn( prevVal, key, val, obj ) { return prevVal + key + ' : ' + val + '; '; } console.log( dataset.reduce( reduceFn, 'initialValue' ) ); 'Output' == 'initialValue; key1 : value1; key2 : value2; key3 : value3; '. 

n'Joy guys !; -)

+4
05 Oct '14 at 11:43
source share

one

 [{value:5}, {value:10}].reduce((previousValue, currentValue) => { return {value: previousValue.value + currentValue.value}}) >> Object {value: 15} 

2:

 [{value:5}, {value:10}].map(item => item.value).reduce((previousValue, currentValue) => {return previousValue + currentValue }) >> 15 

3:

 [{value:5}, {value:10}].reduce(function (previousValue, currentValue) { return {value: previousValue.value + currentValue.value}; }) >> Object {value: 15} 
+3
May 09 '16 at 2:50
source share

You can use the generator expression (supported in all browsers for many years and Node) to get key-value pairs in a list by which you can reduce:

 >>> a = {"b": 3} Object { b=3} >>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))] [["b", 3]] 
+2
Apr 01 '13 at 18:14
source share

Although an object can be turned into its representation of an array using the methods: Object.entries () , Object.keys () , Object.values ​​() , and then reduced to a regular array, I would prefer not to create an intermediate array, just iterate over the object, save memory and cycles!

So, I created a helper function that imitates Array.prototype.reduce () very closely.

 const {hasOwnProperty} = Object.prototype; const reduce = (object, reducer, accumulator) => { for (const key in object) if (hasOwnProperty.call(object, key)) accumulator = reducer(accumulator, object[key], key, object); return accumulator; }; 

You can also assign it

 Object.reduce = reduce; 

since this method is very useful!

So the answer to your question would be:

 result = Object.reduce( { a: {value:1}, b: {value:2}, c: {value:3}, }, (accumulator, current) => (accumulator.value += current.value, accumulator), // reducer function must return accumulator {value: 0} // initial accumulator value ); 
+2
Dec 27 '18 at 12:21
source share

If you can use an array, use an array; the length and order of the array are half worth.

 function reducer(obj, fun, temp){ if(typeof fun=== 'function'){ if(temp== undefined) temp= ''; for(var p in obj){ if(obj.hasOwnProperty(p)){ temp= fun(obj[p], temp, p, obj); } } } return temp; } var O={a:{value:1},b:{value:2},c:{value:3}} reducer(O, function(a, b){return a.value+b;},0); 

/ * return value: (Number) 6 * /

+1
Apr 01 '13 at 18:22
source share

This is not very difficult to implement on your own:

 function reduceObj(obj, callback, initial) { "use strict"; var key, lastvalue, firstIteration = true; if (typeof callback !== 'function') { throw new TypeError(callback + 'is not a function'); } if (arguments.length > 2) { // initial value set firstIteration = false; lastvalue = initial; } for (key in obj) { if (!obj.hasOwnProperty(key)) continue; if (firstIteration) firstIteration = false; lastvalue = obj[key]; continue; } lastvalue = callback(lastvalue, obj[key], key, obj); } if (firstIteration) { throw new TypeError('Reduce of empty object with no initial value'); } return lastvalue; } 

In action:

 var o = {a: {value:1}, b: {value:2}, c: {value:3}}; reduceObj(o, function(prev, curr) { prev.value += cur.value; return prev;}, {value:0}); reduceObj(o, function(prev, curr) { return {value: prev.value + curr.value};}); // both == { value: 6 }; reduceObj(o, function(prev, curr) { return prev + curr.value; }, 0); // == 6 

You can also add it to the prototype of the object:

 if (typeof Object.prototype.reduce !== 'function') { Object.prototype.reduce = function(callback, initial) { "use strict"; var args = Array.prototype.slice(arguments); args.unshift(this); return reduceObj.apply(null, args); } } 
+1
Apr 01 '13 at
source share

Since hasnt really been confirmed in response yet, the underline reduce also works for this.

 _.reduce({ a: {value:1}, b: {value:2}, c: {value:3} }, function(prev, current){ //prev is either first object or total value var total = prev.value || prev return total + current.value }) 

Note that _.reduce will return a single value (an object or another) if the list object has only one element, without calling the iterator function.

 _.reduce({ a: {value:1} }, function(prev, current){ //not called }) //returns {value: 1} instead of 1 
+1
Mar 01 '18 at 0:54
source share

Try this one-liner arrow function

 Object.values(o).map(a => a.value, o).reduce((ac, key, index, arr) => ac+=key) 
0
Jul 25 '19 at 5:30
source share



All Articles