2013-04-01 57 views
84

有很好的數組方法reduce()從數組中獲取一個值。例如:Javascript reduce()對象

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

什麼是實現與對象相同的最佳方式?我想這樣做:

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

但是,對象似乎沒有任何reduce()方法實施。

+1

你使用的是'Underscore.js'嗎? – Sethen

+0

沒有。下劃線是否爲對象提供了減少? –

+0

我不記得了。我知道它有一個「減少」的方法。我會在那裏檢查。雖然,解決方案似乎並不困難。 – Sethen

回答

171

一種選擇將是reducekeys()

var o = { 
    a: {value:1}, 
    b: {value:2}, 
    c: {value:3} 
}; 

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

有了這個,你要指定一個初始值或第一輪將'a' + 2

如果你想作爲一個對象({ value: ... }),你必須初始化,每次返回對象的結果:現在

Object.keys(o).reduce(function (previous, key) { 
    previous.value += o[key].value; 
    return previous; 
}, { value: 0 }); 
+5

不錯的答案,但它更易於使用Object.values而不是Object.keys,因爲我們關心的是這裏的值而不是關鍵。它應該是這樣的: Object.values(o).reduce((total,current)=> total + current.value,0); –

+0

對象。值比Object.keys有更差的瀏覽器支持,但如果使用polyfill或與Babel – duhaime

1

您可以用生成器表達式(在所有的瀏覽器都支持了多年,並在節點),以獲得在列表中的鍵值對,你可以減少:

>>> a = {"b": 3} 
Object { b=3} 

>>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))] 
[["b", 3]] 
14

首先,你沒有完全得到什麼reduce的以前的值。

在你僞代碼中你有return previous.value + current.value,因此previous的值將是下一次調用的數字,而不是對象。

其次,reduce是一個Array方法,而不是對象的一個​​,你不能靠當你遍歷一個對象的屬性的順序(參見:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in,這被應用於Object.keys太);所以我不確定是否將reduce應用於對象是有意義的。

但是,如果順序並不重要,你可以有:

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

或者你可以map對象的值:

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

附:與脂肪箭頭函數的語法(在Firefox每晚的話)ES6,你可以收縮了一下:

Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current); 
1

如果你可以使用一個數組,不要使用數組,長度和順序的排列是其一半價值。

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); 

/*返回值:(數字) */

2

這並不是很難實現自己:

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; 
} 

在行動:

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 

您也可以將其添加到對象原型:

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); 
    } 
} 
4

擴展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); 
}; 

使用樣本。

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它,夥計們! ;-)

+0

-1一起傳輸,那麼這可能不是問題,現在您對所有將來的對象都有一個新的枚舉屬性:http:// jsfiddle。 net/ygonjooh/ – Johan

+1

「hasOwnProperty()」將有助於U. http://jsfiddle.net/rain/ygonjooh/1/ – user1247458

2

1:

[{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} 
12

ES6實現: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); 
+2

Object.entries(o); //返回[['value',1],['value',2],['value',3]]' – faboulaws

+0

const [key,value] = pair;我從來沒有見過這個! –

+0

@ martin-meeser--這就是所謂的解構。我們甚至可以通過將'function(total,pair)'改成'function(total,[key,value])來省略這一行' –

7

你在這種情況下實際需要的是Object.values。這裏是一個簡潔的ES6實施考慮到這一點:

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 

或者乾脆:

add = { 
    a: 1, 
    b: 2, 
    c: 3 
} 

total = Object.values(add).reduce((t, n) => t + n) 

console.log(total) // 6 
+0

這就是您鏈接到的Array.prototype.values() - 現在編輯 –

+0

好的捕獲。 .. –

0

由於它未真正得到的答案卻證實,下劃線的reduce也適用於這一點。

_.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 
}) 

注意,_.reduce將返回唯一值(對象或其他方式),如果列表對象只有一個項目,而無需調用迭代器的功能。

_.reduce({ 
    a: {value:1} 
}, function(prev, current){ 
    //not called 
}) 

//returns {value: 1} instead of 1