对象上的 Javascript reduce()
Posted
技术标签:
【中文标题】对象上的 Javascript reduce()【英文标题】:Javascript reduce() on Object 【发布时间】:2013-03-22 20:02:33 【问题描述】:有一个很好的数组方法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;
);
但是,Object 似乎没有实现任何reduce()
方法。
【问题讨论】:
你在用Underscore.js
吗?
不。 Underscore 是否为对象提供 reduce 功能?
我不记得了。我知道它有一个reduce
方法。我会在那里检查。不过,解决方案似乎并不难。
@Sethen Maleno,@Pavel:是的,_
确实有对象的归约。不确定它是否是偶然的,或者对象支持是否是故意的,但确实你可以像这个问题的例子一样传递一个对象,它会(从概念上)for..in
,用每个键找到的值调用你的迭代器函数。
【参考方案1】:
一种选择是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);
有了这个,您需要指定一个初始值,否则第一轮将是'a' + 2
。
如果您希望将结果作为对象 ( value: ...
),则每次都必须初始化并返回该对象:
Object.keys(o).reduce(function (previous, key)
previous.value += o[key].value;
return previous;
, value: 0 );
【讨论】:
不错的答案,但使用 Object.values 而不是 Object.keys 更具可读性,因为我们关心的是这里的值而不是键。应该是这样的: Object.values(o).reduce((total, current) => total + current.value, 0); Object.values 的浏览器支持比 Object.keys 差得多,但如果您使用 polyfill 或使用 Babel 进行转译,这可能不是问题 确切地说,我在从 mongo 模型中检索到的甜菜键中使用它,并且我将一个空对象作为初始值传递给键的减少结果,就像我使用 @ 987654328@插件,我被传播了累加器值以换取reduce,它就像一个魅力,但我想知道我是否做错了什么,因为我将对象传递给reduce的初始值,你的回答证明了我我做对了! 但是使用 Object.values 并不能让您访问正在使用的实际密钥。使用 key ,特别是在归约中,是很常见的 还有——除了示例之外——谁有他们想要简单总结的对象属性列表?大多数时候对象属性是不同的。【参考方案2】:您可以使用生成器表达式(多年来在所有浏览器中以及在 Node 中都支持)来获取可以减少的列表中的键值对:
>>> a = "b": 3
Object b=3
>>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))]
[["b", 3]]
【讨论】:
【参考方案3】:首先,你不太明白 reduce 之前的值是什么。
在您的伪代码中,您有return previous.value + current.value
,因此previous
值将是下一次调用时的数字,而不是对象。
其次,reduce
是一个 Array 方法,而不是 Object 的方法,并且在迭代对象的属性时不能依赖顺序(参见:https://developer.mozilla.org/en-US/docs/javascript/Reference/Statements/for...in,这适用于 @987654323 @ 也);所以我不确定在对象上应用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;
);
附:在 ES6 中使用胖箭头函数的语法(已经在 Firefox Nightly 中),你可以缩小一点:
Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current);
【讨论】:
【参考方案4】:如果你可以使用数组,请使用数组,数组的长度和顺序是它的一半。
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);
/* 返回值:(数字) 6 */
【讨论】:
【参考方案5】:这不是很难自己实现:
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
您也可以将其添加到 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);
【讨论】:
【参考方案6】:扩展 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 it,伙计们! ;-)
【讨论】:
-1,现在您在所有未来对象上都有一个新的可枚举属性:jsfiddle.net/ygonjooh Don't modify objects you don't own. 请不要这样修改基础原型。这可能会给未来使用相同代码库的开发人员带来很多问题 是的,这是一个“猴子补丁”这个解决方案是6年前写的,现在不太相关,请记住,例如,在2021年使用Object.entries()
会更好
【参考方案7】:
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
【讨论】:
【参考方案8】: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.value;
, 0);
【讨论】:
Object.entries(o); // returns [['value',1],['value',2],['value',3]]
const [键,值] = 对;我从来没有见过这个!
@martin-meeser - 这称为解构。我们甚至可以通过将function (total, pair)
更改为function (total, [key, value])
来省略这一行
@faboulaws Object.entries(o); // 返回 [["a", value: 1 ], ["b", value: 2 ], ["c", value: 3 ]]
@faboulaws 你的回答错了,最后一行应该是return total + value.value
。因为 Object.entries(o) [ [ "a", "value": 1 ], [ "b", "value": 2 ], [ "c", "value": 3 ] ]
,这是非常具有误导性的。甚至有 3 个人竖起大拇指...【参考方案9】:
在这种情况下,您真正想要的是Object.values
。考虑到这一点,这是一个简洁的 ES6 实现:
const add =
a: value:1,
b: value:2,
c: value:3
const total = Object.values(add).reduce((t, value) => t + value, 0)
console.log(total) // 6
或者简单地说:
const add =
a: 1,
b: 2,
c: 3
const total = Object.values(add).reduce((t, n) => t + n)
console.log(total) // 6
【讨论】:
这是您链接到的 Array.prototype.values() - 现在已编辑 不会reduce把默认值作为第二个参数吗?【参考方案10】:由于尚未真正在答案中得到确认,Underscore 的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
【讨论】:
你是说lodash? 不,我的意思是下划线。但两者都有效。他们都有reduce()
哎呀,我从来没有听说过下划线谢谢。【参考方案11】:
一个对象可以变成一个数组:Object.entries(),Object.keys(),Object.values(),然后被归约为数组。但是您也可以在不创建中间数组的情况下减少对象。
我创建了一个小助手库odict 用于处理对象。
npm install --save odict
它具有reduce
功能,非常类似于Array.prototype.reduce():
export const reduce = (dict, reducer, accumulator) =>
for (const key in dict)
accumulator = reducer(accumulator, dict[key], key, dict);
return accumulator;
;
您也可以将其分配给:
Object.reduce = reduce;
因为这个方法非常有用!
所以你的问题的答案是:
const 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
);
【讨论】:
【参考方案12】:试试这个单线箭头功能
Object.values(o).map(a => a.value, o).reduce((ac, key, index, arr) => ac+=key)
【讨论】:
“试试这个”的答案在 Stack Overflow 上的价值很低,因为他们错过了赋能/教育成千上万未来研究人员的机会。【参考方案13】:试试这个。它将从其他变量中对数字进行排序。
const obj =
a: 1,
b: 2,
c: 3
;
const result = Object.keys(obj)
.reduce((acc, rec) => typeof obj[rec] === "number" ? acc.concat([obj[rec]]) : acc, [])
.reduce((acc, rec) => acc + rec)
【讨论】:
【参考方案14】:如果作为数组处理会容易得多
返回水果的总量:
let fruits = [ name: 'banana', id: 0, quantity: 9 , name: 'strawberry', id: 1, quantity: 1 , name: 'kiwi', id: 2, quantity: 2 , name: 'apple', id: 3, quantity: 4 ]
let total = fruits.reduce((sum, f) => sum + f.quantity, 0);
【讨论】:
【参考方案15】:让我总结一下可能性。目标始终是从对象中创建一个数组。为此有各种 Javascript 对象函数。对于每个单独的函数,都有不同的解释方式。所以它总是取决于我们的对象是什么样子以及我们想要做什么。
在上面的例子中,它是一个包含三个对象的对象。
const obj =
a: value: 1,
b: value: 2,
c: value:3
;
使用 Object.keys
Object.keys 只给我们对象的键。
const arr = Object.keys(obj);
// output arr:
[a, b, c]
const result = arr.reduce((total, key) =>
return sum + obj[key].value;
, 0);
// output result
// 6
使用 Object.value
Object.value() 返回数组中的每一个值。
const arr = Object.value(obj);
// output arr
[
value: 1,
value: 2,
value: 3,
]
const result = arr.reduce((total, singleValue) =>
return total + singleValue.value;
, 0);
// output result
// 6
// Or the short variant
const resultShort = Object.values(obj).reduce((t, n) => t + n.value, 0)
// output resultShort
// 6
使用 Object.entries
Object.entries 将每个单独的对象值拆分为一个数组。
const arr = Object.entries(obj)
// output arr
[
["a", visitors: 1],
["b", visitors: 2],
["c", visitors: 4]
]
const result = arr.reduce((total, singleArr) =>
return total + singleArr[1].value;
, 0);
// output result
// 6
你是使用reduce还是使用数组函数map()取决于你和你想要做什么。
【讨论】:
以上是关于对象上的 Javascript reduce()的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 基于reduce方法实现数组内对象的同属性运算
如何使用 reduce 函数 javascript 对对象进行分组
javascript 使用Array reduce可以安全地访问嵌套对象。
Javascript 中使用 Array.reduce 的相同对象的总和