如何对对象数组调用reduce来求和它们的属性?

发布于 2024-11-02 08:55:51 字数 428 浏览 5 评论 0原文

假设我想对 arr 中的每个元素求和 ax。

arr = [ { x: 1 }, { x: 2 }, { x: 4 } ];
arr.reduce(function(a, b){ return a.x + b.x; }); // => NaN

我有理由相信 ax 在某些时候是 undefined

以下工作正常

arr = [ 1, 2, 4 ];
arr.reduce(function(a, b){ return a + b; }); // => 7

我在第一个示例中做错了什么?

Say I want to sum a.x for each element in arr.

arr = [ { x: 1 }, { x: 2 }, { x: 4 } ];
arr.reduce(function(a, b){ return a.x + b.x; }); // => NaN

I have cause to believe that a.x is undefined at some point.

The following works fine

arr = [ 1, 2, 4 ];
arr.reduce(function(a, b){ return a + b; }); // => 7

What am I doing wrong in the first example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

骷髅 2024-11-09 08:55:51

实现此目的的一种更简洁的方法是提供一个初始值作为 reduce 的第二个参数:

var arr = [{x:1}, {x:2}, {x:4}];
var result = arr.reduce(function (acc, obj) { return acc + obj.x; }, 0);
console.log(result);  // 7

第一次调用匿名函数时,会使用 (0, {x: 1}) 调用它并返回 0 + 1 = 1。下一次,它会被 (1, {x: 2}) 调用并返回 1 + 2 = 3。然后使用 (3, {x: 4}) 调用它,最终返回 7

这也处理数组为空的情况,返回0

A cleaner way to accomplish this is by providing an initial value as the second argument to reduce:

var arr = [{x:1}, {x:2}, {x:4}];
var result = arr.reduce(function (acc, obj) { return acc + obj.x; }, 0);
console.log(result);  // 7

The first time the anonymous function is called, it gets called with (0, {x: 1}) and returns 0 + 1 = 1. The next time, it gets called with (1, {x: 2}) and returns 1 + 2 = 3. It's then called with (3, {x: 4}), finally returning 7.

This also handles the case where the array is empty, returning 0.

り繁华旳梦境 2024-11-09 08:55:51

第一次迭代后,您返回一个数字,然后尝试获取它的属性x以添加到下一个未定义对象以及涉及未定义<的数学/code> 结果为 NaN

尝试返回一个包含 x 属性的对象,其中包含参数的 x 属性的总和:

var arr = [{x:1},{x:2},{x:4}];

arr.reduce(function (a, b) {
  return {x: a.x + b.x}; // returns object with property x
})

// ES6
arr.reduce((a, b) => ({x: a.x + b.x}));

// -> {x: 7}

从注释中添加的解释:

使用的 [].reduce 每次迭代的返回值作为下一次迭代中的 a 变量。

迭代 1:a = {x:1}b = {x:2}{x: 3} 分配给 迭代 2 中的 a

迭代 2:a = {x:3}b = {x:4}

您的示例的问题是您返回的是数字文字。

function (a, b) {
  return a.x + b.x; // returns number literal
}

迭代 1:a = {x:1}b = {x:2}// 返回 3 作为 a< /code> 在下一次迭代

迭代 2 中:a = 3b = {x:2} 返回 NaN

数字文字 3(通常)没有名为 x 的属性,因此它是 undefined 并且 undefined + bx 返回 NaN > 和 NaN + 始终为 NaN

澄清:我更喜欢我的方法而不是这个线程中的其他最佳答案,因为我不同意传递可选参数以使用幻数进行归约以得到数字原语的想法更清晰。它可能会导致写入的行数减少,但在我看来它的可读性较差。

After the first iteration your're returning a number and then trying to get property x of it to add to the next object which is undefined and maths involving undefined results in NaN.

try returning an object contain an x property with the sum of the x properties of the parameters:

var arr = [{x:1},{x:2},{x:4}];

arr.reduce(function (a, b) {
  return {x: a.x + b.x}; // returns object with property x
})

// ES6
arr.reduce((a, b) => ({x: a.x + b.x}));

// -> {x: 7}

Explanation added from comments:

The return value of each iteration of [].reduce used as the a variable in the next iteration.

Iteration 1: a = {x:1}, b = {x:2}, {x: 3} assigned to a in Iteration 2

Iteration 2: a = {x:3}, b = {x:4}.

The problem with your example is that you're returning a number literal.

function (a, b) {
  return a.x + b.x; // returns number literal
}

Iteration 1: a = {x:1}, b = {x:2}, // returns 3 as a in next iteration

Iteration 2: a = 3, b = {x:2} returns NaN

A number literal 3 does not (typically) have a property called x so it's undefined and undefined + b.x returns NaN and NaN + <anything> is always NaN

Clarification: I prefer my method over the other top answer in this thread as I disagree with the idea that passing an optional parameter to reduce with a magic number to get out a number primitive is cleaner. It may result in fewer lines written but imo it is less readable.

真心难拥有 2024-11-09 08:55:51

TL;DR,设置初始值

使用 解构

arr.reduce( ( sum, { x } ) => sum + x , 0)

不解构

arr.reduce( ( sum , cur ) => sum + cur.x , 0)

使用 TypeScript

arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)< /code>

让我们尝试一下解构方法:

const arr = [ { x: 1 }, { x: 2 }, { x: 4 } ]
const result = arr.reduce( ( sum, { x } ) => sum + x , 0)
console.log( result ) // 7

其关键在于初始值的设定。返回值成为下一次迭代的第一个参数。

最佳答案中使用的技术不是惯用

的 接受的答案建议不传递“可选”值。这是错误的,因为惯用的方法是始终包含第二个参数。为什么?三个原因:

1。危险
-- 不传入初始值是危险的,如果回调函数不小心,可能会产生副作用和突变。

看吧:

const badCallback = (a,i) => Object.assign(a,i)

const foo = [ { a: 1 }, { b: 2 }, { c: 3 } ]
const bar = foo.reduce( badCallback )  // bad use of Object.assign
// Look, we've tampered with the original array
foo //  [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

但是,如果我们这样做,初始值是:

const bar = foo.reduce( badCallback, {})
// foo is still OK
foo // { a: 1, b: 2, c: 3 }

根据记录,除非您打算改变原始对象,否则请将 Object.assign 的第一个参数设置为空对象。像这样:Object.assign({}, a, b, c)

2 - 更好的类型推断
--当使用像 TypeScript 这样的工具或像 VS Code 这样的编辑器时,您可以通过告诉编译器初始值来获得好处,并且如果您做错了,它可以捕获错误。如果您不设置初始值,在许多情况下它可能无法猜测,并且最终可能会出现令人毛骨悚然的运行时错误。

3 - 尊重函子
——当 JavaScript 的内部函数子被释放出来时,它就会发挥出最大的光芒。在函数世界中,有一个关于如何“折叠”或减少数组的标准。当您将 catamorphism 折叠或应用到数组时,您将使用该数组的值来构造一个新型。您需要传达结果类型 - 即使最终类型是数组、另一个数组或任何其他类型中的值,您也应该这样做。

让我们换个角度思考一下。在 JavaScript 中,函数可以像数据一样传递,这就是回调的工作原理,以下代码的结果是什么?

[1,2,3].reduce(callback)

会返回一个数字吗?一个物体?这使得它更清晰

[1,2,3].reduce(callback,0)

在此处阅读有关函数式编程规范的更多信息:https://github.com/fantasyland/fantasy-land#foldable

更多背景信息

reduce 方法采用两个参数,

Array.prototype.reduce( callback, initialItem )

回调函数采用以下参数

(accumulator, itemInArray, indexInArray, entireArray) => { /* do stuff */ }

对于第一次迭代,

  • 如果提供了 initialItem,则 reduce 函数将 initialItem 作为累加器传递 并将数组的第一项作为 itemInArray

  • 如果提供initialItem,则reduce函数将数组中的第一项作为initialItem传递数组中的第二项为 itemInArray,这可能会造成混淆。

我教导并建议始终设置reduce 的初始值。

您可以在以下位置查看文档:

https:// /developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

TL;DR, set the initial value

Using destructuring

arr.reduce( ( sum, { x } ) => sum + x , 0)

Without destructuring

arr.reduce( ( sum , cur ) => sum + cur.x , 0)

With TypeScript

arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)

Let's try the destructuring method:

const arr = [ { x: 1 }, { x: 2 }, { x: 4 } ]
const result = arr.reduce( ( sum, { x } ) => sum + x , 0)
console.log( result ) // 7

The key to this is setting initial value. The return value becomes first parameter of the next iteration.

Technique used in top answer is not idiomatic

The accepted answer proposes NOT passing the "optional" value. This is wrong, as the idiomatic way is that the second parameter always be included. Why? Three reasons:

1. Dangerous
-- Not passing in the initial value is dangerous and can create side-effects and mutations if the callback function is careless.

Behold:

const badCallback = (a,i) => Object.assign(a,i)

const foo = [ { a: 1 }, { b: 2 }, { c: 3 } ]
const bar = foo.reduce( badCallback )  // bad use of Object.assign
// Look, we've tampered with the original array
foo //  [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

If however we had done it this way, with the initial value:

const bar = foo.reduce( badCallback, {})
// foo is still OK
foo // { a: 1, b: 2, c: 3 }

For the record, unless you intend to mutate the original object, set the first parameter of Object.assign to an empty object. Like this: Object.assign({}, a, b, c).

2 - Better Type Inference
--When using a tool like TypeScript or an editor like VS Code, you get the benefit of telling the compiler the initial and it can catch errors if you're doing it wrong. If you don't set the initial value, in many situations it might not be able to guess and you could end up with creepy runtime errors.

3 - Respect the Functors
-- JavaScript shines best when its inner functional child is unleashed. In the functional world, there is a standard on how you "fold" or reduce an array. When you fold or apply a catamorphism to the array, you take the values of that array to construct a new type. You need to communicate the resulting type--you should do this even if the final type is that of the values in the array, another array, or any other type.

Let's think about it another way. In JavaScript, functions can be passed around like data, this is how callbacks work, what is the result of the following code?

[1,2,3].reduce(callback)

Will it return an number? An object? This makes it clearer

[1,2,3].reduce(callback,0)

Read more on the functional programming spec here: https://github.com/fantasyland/fantasy-land#foldable

Some more background

The reduce method takes two parameters,

Array.prototype.reduce( callback, initialItem )

The callback function takes the following parameters

(accumulator, itemInArray, indexInArray, entireArray) => { /* do stuff */ }

For the first iteration,

  • If initialItem is provided, the reduce function passes the initialItem as the accumulator and the first item of the array as the itemInArray.

  • If initialItem is not provided, the reduce function passes the first item in the array as the initialItem and the second item in the array as itemInArray which can be confusing behavior.

I teach and recommend always setting the initial value of reduce.

You can check out the documentation at:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

孤独患者 2024-11-09 08:55:51

其他人已经回答了这个问题,但我想我应该采用另一种方法。您可以组合一个映射(从 ax 到 x)并减少(添加 x),而不是直接求和 ax:

arr = [{x:1},{x:2},{x:4}]
arr.map(function(a) {return a.x;})
   .reduce(function(a,b) {return a + b;});

诚然,它可能会稍微慢一些,但我认为值得一提的是它作为一个选项。

Others have answered this question, but I thought I'd toss in another approach. Rather than go directly to summing a.x, you can combine a map (from a.x to x) and reduce (to add the x's):

arr = [{x:1},{x:2},{x:4}]
arr.map(function(a) {return a.x;})
   .reduce(function(a,b) {return a + b;});

Admittedly, it's probably going to be slightly slower, but I thought it worth mentioning it as an option.

浅忆 2024-11-09 08:55:51

为了形式化所指出的内容,reducer 是一种变形,它接受两个可能巧合为同一类型的参数,并返回与第一个参数匹配的类型。

function reducer (accumulator: X, currentValue: Y): X { }

这意味着减速器的主体需要将 currentValueaccumulator 的当前值转换为新的 accumulator 的值。

在添加时,这是一种简单的方式,因为累加器和元素值恰好是相同的类型(但服务于不同的目的)。

[1, 2, 3].reduce((x, y) => x + y);

这之所以有效,是因为它们都是数字。

[{ age: 5 }, { age: 2 }, { age: 8 }]
  .reduce((total, thing) => total + thing.age, 0);

现在我们为聚合器提供一个起始值。在绝大多数情况下,起始值应该是您期望聚合器的类型(您期望作为最终值出现的类型)。
虽然您没有被迫这样做(也不应该这样做),但请记住这一点很重要。

一旦了解了这一点,您就可以为其他 n:1 关系问题编写有意义的简化。

删除重复的单词:

const skipIfAlreadyFound = (words, word) => words.includes(word)
    ? words
    : words.concat(word);

const deduplicatedWords = aBunchOfWords.reduce(skipIfAlreadyFound, []);

提供找到的所有单词的计数:

const incrementWordCount = (counts, word) => {
  counts[word] = (counts[word] || 0) + 1;
  return counts;
};
const wordCounts = words.reduce(incrementWordCount, { });

将数组数组缩减为单个平面数组:

const concat = (a, b) => a.concat(b);

const numbers = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
].reduce(concat, []);

任何时候您想要从一组事物变为与 1 不匹配的单个值: 1、减少是你可以考虑的事情。

事实上,map 和filter 都可以实现为归约:

const map = (transform, array) =>
  array.reduce((list, el) => list.concat(transform(el)), []);

const filter = (predicate, array) => array.reduce(
  (list, el) => predicate(el) ? list.concat(el) : list,
  []
);

我希望这为如何使用reduce 提供了一些进一步的背景信息。

我还没有深入探讨的一个补充是,当期望输入和输出类型专门是动态的时,因为数组元素是函数:

const compose = (...fns) => x =>
  fns.reduceRight((x, f) => f(x), x);

const hgfx = h(g(f(x)));
const hgf = compose(h, g, f);
const hgfy = hgf(y);
const hgfz = hgf(z);

To formalize what has been pointed out, a reducer is a catamorphism which takes two arguments which may be the same type by coincidence, and returns a type which matches the first argument.

function reducer (accumulator: X, currentValue: Y): X { }

That means that the body of the reducer needs to be about converting currentValue and the current value of the accumulator to the value of the new accumulator.

This works in a straightforward way, when adding, because the accumulator and the element values both happen to be the same type (but serve different purposes).

[1, 2, 3].reduce((x, y) => x + y);

This just works because they're all numbers.

[{ age: 5 }, { age: 2 }, { age: 8 }]
  .reduce((total, thing) => total + thing.age, 0);

Now we're giving a starting value to the aggregator. The starting value should be the type that you expect the aggregator to be (the type you expect to come out as the final value), in the vast majority of cases.
While you aren't forced to do this (and shouldn't be), it's important to keep in mind.

Once you know that, you can write meaningful reductions for other n:1 relationship problems.

Removing repeated words:

const skipIfAlreadyFound = (words, word) => words.includes(word)
    ? words
    : words.concat(word);

const deduplicatedWords = aBunchOfWords.reduce(skipIfAlreadyFound, []);

Providing a count of all words found:

const incrementWordCount = (counts, word) => {
  counts[word] = (counts[word] || 0) + 1;
  return counts;
};
const wordCounts = words.reduce(incrementWordCount, { });

Reducing an array of arrays, to a single flat array:

const concat = (a, b) => a.concat(b);

const numbers = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
].reduce(concat, []);

Any time you're looking to go from an array of things, to a single value that doesn't match a 1:1, reduce is something you might consider.

In fact, map and filter can both be implemented as reductions:

const map = (transform, array) =>
  array.reduce((list, el) => list.concat(transform(el)), []);

const filter = (predicate, array) => array.reduce(
  (list, el) => predicate(el) ? list.concat(el) : list,
  []
);

I hope this provides some further context for how to use reduce.

The one addition to this, which I haven't broken into yet, is when there is an expectation that the input and output types are specifically meant to be dynamic, because the array elements are functions:

const compose = (...fns) => x =>
  fns.reduceRight((x, f) => f(x), x);

const hgfx = h(g(f(x)));
const hgf = compose(h, g, f);
const hgfy = hgf(y);
const hgfz = hgf(z);
Bonjour°[大白 2024-11-09 08:55:51

对于第一次迭代,“a”将是数组中的第一个对象,因此 ax + bx 将返回 1+2,即 3。

现在,在下一次迭代中,返回的 3 被分配给 a,因此 a现在n是一个数字,调用ax将给出NaN

简单的解决方案是首先映射数组中的数字,然后按如下方式减少它们:

arr.map(a=>a.x).reduce(function(a,b){return a+b})

这里 arr.map(a=>ax) 将提供一个数字数组 [1,2,4],现在使用 < code>.reduce(function(a,b){return a+b}) 将简单地将这些数字相加,没有任何麻烦

另一个简单的解决方案是将 0 分配给 a 来提供初始总和为零如下:

arr.reduce(function(a,b){return a + b.x},0)

For the first iteration 'a' will be the first object in the array, hence a.x + b.x will return 1+2 i.e. 3.

Now in the next iteration the returned 3 is assigned to a, so a is a number now n calling a.x will give NaN.

Simple solution is first mapping the numbers in array and then reducing them as below:

arr.map(a=>a.x).reduce(function(a,b){return a+b})

here arr.map(a=>a.x) will provide an array of numbers [1,2,4] now using .reduce(function(a,b){return a+b}) will simple add these numbers without any hassel

Another simple solution is just to provide an initial sum as zero by assigning 0 to a as below:

arr.reduce(function(a,b){return a + b.x},0)
戒ㄋ 2024-11-09 08:55:51

如果您有一个包含大量数据的复杂对象(例如对象数组),您可以采取逐步方法来解决此问题。

例如:

const myArray = [{ id: 1, value: 10}, { id: 2, value: 20}];

首先,您应该将数组映射到您感兴趣的新数组中,在本例中它可能是一个新的值数组。

const values = myArray.map(obj => obj.value);

此回调函数将返回一个仅包含原始数组中的值的新数组,并将其存储在常量值中。现在你的values const 是一个像这样的数组:

values = [10, 20];

现在你已经准备好执行reduce了:

const sum = values.reduce((accumulator, currentValue) => { return accumulator + currentValue; } , 0);

正如你所看到的,reduce方法多次执行回调函数。每次,它都会获取数组中项目的当前值并与累加器求和。因此,要正确求和,您需要将累加器的初始值设置为 reduce 方法的第二个参数。

现在您有了新的 const sum,其值为 30。

If you have a complex object with a lot of data, like an array of objects, you can take a step by step approach to solve this.

For e.g:

const myArray = [{ id: 1, value: 10}, { id: 2, value: 20}];

First, you should map your array into a new array of your interest, it could be a new array of values in this example.

const values = myArray.map(obj => obj.value);

This call back function will return a new array containing only values from the original array and store it on values const. Now your values const is an array like this:

values = [10, 20];

And now your are ready to perform your reduce:

const sum = values.reduce((accumulator, currentValue) => { return accumulator + currentValue; } , 0);

As you can see, the reduce method executes the call back function multiple times. For each time, it takes the current value of the item in the array and sum with the accumulator. So to properly sum it you need to set the initial value of your accumulator as the second argument of the reduce method.

Now you have your new const sum with the value of 30.

话少情深 2024-11-09 08:55:51

在归约的每一步中,您都不会返回新的 {x:???} 对象。所以你要么需要做:

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a + b.x})

要么你需要做

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return {x: a.x + b.x}; }) 

At each step of your reduce, you aren't returning a new {x:???} object. So you either need to do:

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a + b.x})

or you need to do

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return {x: a.x + b.x}; }) 
水中月 2024-11-09 08:55:51

我在 ES6 中做了一点改进:

arr.reduce((a, b) => ({x: a.x + b.x})).x

返回数字

I did it in ES6 with a little improvement:

arr.reduce((a, b) => ({x: a.x + b.x})).x

return number

说好的呢 2024-11-09 08:55:51

在第一步中,它会正常工作,因为 a 的值为 1,b 的值为 2,但在下一步中将返回 2+1步骤 b 的值将是步骤 1 的返回值,即 3,因此 bx 将是未定义的...并且 undefined + anyNumber 将为 NaN,这就是你得到这个结果的原因。

相反,您可以通过将初始值设置为零来尝试此操作,即

arr.reduce(function(a,b){return a + b.x},0);

In the first step, it will work fine as the value of a will be 1 and that of b will be 2 but as 2+1 will be returned and in the next step the value of b will be the return value from step 1 i.e 3 and so b.x will be undefined...and undefined + anyNumber will be NaN and that is why you are getting that result.

Instead you can try this by giving initial value as zero i.e

arr.reduce(function(a,b){return a + b.x},0);

迷乱花海 2024-11-09 08:55:51

我曾经在我的开发中遇到过这种情况,我所做的是将我的解决方案包装在一个函数中,使其可以在我的环境中重用,如下所示:

const sumArrayOfObject =(array, prop)=>array.reduce((sum, n)=>{return sum + n[prop]}, 0)

I used to encounter this is my development, what I do is wrap my solution in a function to make it reusable in my environment, like this:

const sumArrayOfObject =(array, prop)=>array.reduce((sum, n)=>{return sum + n[prop]}, 0)
心安伴我暖 2024-11-09 08:55:51

只是我的 2 美分关于使用对象文字设置默认值。

  let arr = [{
        duration: 1
    }, {
        duration: 3
    }, {
        duration: 5
    }, {
        duration: 6
    }];
    
    const out = arr.reduce((a, b) => {
        return {
            duration: a.duration + b.duration
        };
    }, {
        duration: 0
    });
    
    console.log(out);

Just my 2 cents on setting a default value with object literal.

  let arr = [{
        duration: 1
    }, {
        duration: 3
    }, {
        duration: 5
    }, {
        duration: 6
    }];
    
    const out = arr.reduce((a, b) => {
        return {
            duration: a.duration + b.duration
        };
    }, {
        duration: 0
    });
    
    console.log(out);

北音执念 2024-11-09 08:55:51
let temp =[{x:1},
{x:2},
{x:3},
{x:4}];
let sum = temp.map(element => element.x).reduce((a, b) => a+ b , 0)
console.log(sum);

我们可以用这种方式求 x

输出的总和:10

let temp =[{x:1},
{x:2},
{x:3},
{x:4}];
let sum = temp.map(element => element.x).reduce((a, b) => a+ b , 0)
console.log(sum);

we can used this way for sum of x

Output : 10

仄言 2024-11-09 08:55:51

您可以使用reduce方法,如下所示;如果将 0(零)更改为 1 或其他数字,它会将其添加到总数中。例如,本示例给出的总数为 31,但是如果我们将 0 更改为 1,总数将为 32。

const batteryBatches = [4, 5, 3, 4, 4, 6, 5];

let totalBatteries= batteryBatches.reduce((acc,val) => acc + val ,0)

You can use reduce method as bellow; If you change the 0(zero) to 1 or other numbers, it will add it to total number. For example, this example gives the total number as 31 however if we change 0 to 1, total number will be 32.

const batteryBatches = [4, 5, 3, 4, 4, 6, 5];

let totalBatteries= batteryBatches.reduce((acc,val) => acc + val ,0)
谜兔 2024-11-09 08:55:51
function aggregateObjectArrayByProperty(arr, propReader, aggregator, initialValue) {
  const reducer = (a, c) => {
    return aggregator(a, propReader(c));
  };
  return arr.reduce(reducer, initialValue);
}

const data = [{a: 'A', b: 2}, {a: 'A', b: 2}, {a: 'A', b: 3}];

let sum = aggregateObjectArrayByProperty(data, function(x) { return x.b; }, function(x, y) { return x + y; }, 0);
console.log(`Sum = ${sum}`);
console.log(`Average = ${sum / data.length}`);

let product = aggregateObjectArrayByProperty(data, function(x) { return x.b; }, function(x, y) { return x * y; }, 1);
console.log(`Product = ${product}`);

刚刚根据之前给出的解决方案编写了一个通用函数。我是一名 Java 开发人员,因此对任何错误或非 javascript 标准表示歉意:-)

function aggregateObjectArrayByProperty(arr, propReader, aggregator, initialValue) {
  const reducer = (a, c) => {
    return aggregator(a, propReader(c));
  };
  return arr.reduce(reducer, initialValue);
}

const data = [{a: 'A', b: 2}, {a: 'A', b: 2}, {a: 'A', b: 3}];

let sum = aggregateObjectArrayByProperty(data, function(x) { return x.b; }, function(x, y) { return x + y; }, 0);
console.log(`Sum = ${sum}`);
console.log(`Average = ${sum / data.length}`);

let product = aggregateObjectArrayByProperty(data, function(x) { return x.b; }, function(x, y) { return x * y; }, 1);
console.log(`Product = ${product}`);

Just wrote a generic function from previously given solutions. I am a Java developer, so apologies for any mistakes or non-javascript standards :-)

梦回梦里 2024-11-09 08:55:51

通用打字稿函数:

const sum = <T>(array: T[], predicate: (value: T, index: number, array: T[]) => number) => {
      return array.reduce((acc, value, index, array) => {
        return acc + predicate(value, index, array);
      }, 0);
    };

示例:

const s = sum(arr, (e) => e.x);

A generic typescript function:

const sum = <T>(array: T[], predicate: (value: T, index: number, array: T[]) => number) => {
      return array.reduce((acc, value, index, array) => {
        return acc + predicate(value, index, array);
      }, 0);
    };

Example:

const s = sum(arr, (e) => e.x);
小耗子 2024-11-09 08:55:51
var arr = [{x:1}, {x:2}, {x:3}];
arr.map(function(a) {return a.x;})
.reduce(function(a, b) {return a + b});
console.log(arr);
//I tried using the following code and the result is the data array
//result = [{x:1}, {x:2}, {x:3}];
var arr2 = [{x:1}, {x:2}, {x:3}]
.reduce((total, thing) => total + thing.x, 0);
console.log(arr2);
// and I changed the code to like this and it worked.
// result = 6
var arr = [{x:1}, {x:2}, {x:3}];
arr.map(function(a) {return a.x;})
.reduce(function(a, b) {return a + b});
console.log(arr);
//I tried using the following code and the result is the data array
//result = [{x:1}, {x:2}, {x:3}];
var arr2 = [{x:1}, {x:2}, {x:3}]
.reduce((total, thing) => total + thing.x, 0);
console.log(arr2);
// and I changed the code to like this and it worked.
// result = 6
无名指的心愿 2024-11-09 08:55:51

我们可以使用数组reduce方法来创建新对象,我们可以使用此选项来求和或过滤

const FRUITS = ["apple", "orange"]
const fruitBasket = {banana: {qty: 10, kg:3}, apple: {qty: 30, kg:10}, orange: {qty: 1, kg:3}}

const newFruitBasket = FRUITS.reduce((acc, fruit) => ({ ...acc, [fruit]: fruitBasket[fruit]}), {})

console.log(newFruitBasket) 

We can use array reduce method to create new Object and we can use this option to sum or filter

const FRUITS = ["apple", "orange"]
const fruitBasket = {banana: {qty: 10, kg:3}, apple: {qty: 30, kg:10}, orange: {qty: 1, kg:3}}

const newFruitBasket = FRUITS.reduce((acc, fruit) => ({ ...acc, [fruit]: fruitBasket[fruit]}), {})

console.log(newFruitBasket) 

德意的啸 2024-11-09 08:55:51

reduce 函数迭代集合

arr = [{x:1},{x:2},{x:4}] // is a collection

arr.reduce(function(a,b){return a.x + b.x})

转换为:

arr.reduce(
    //for each index in the collection, this callback function is called
  function (
    a, //a = accumulator ,during each callback , value of accumulator is 
         passed inside the variable "a"
    b, //currentValue , for ex currentValue is {x:1} in 1st callback
    currentIndex,
    array
  ) {
    return a.x + b.x; 
  },
  accumulator // this is returned at the end of arr.reduce call 
    //accumulator = returned value i.e return a.x + b.x  in each callback. 
);

在每个索引回调期间,变量“accumulator”的值为
传递到回调函数中的“a”参数。如果我们不初始化“accumulator”,它的值将是未定义的。调用 undefined.x 会出现错误。

要解决此问题,请使用值0初始化“累加器”,如上面凯西的回答所示。

要了解“reduce”函数的输入输出,我建议您查看该函数的源代码。
Lodash库有reduce函数,其工作原理与ES6中的“reduce”函数完全相同。

这是链接:
减少源代码

reduce function iterates over a collection

arr = [{x:1},{x:2},{x:4}] // is a collection

arr.reduce(function(a,b){return a.x + b.x})

translates to:

arr.reduce(
    //for each index in the collection, this callback function is called
  function (
    a, //a = accumulator ,during each callback , value of accumulator is 
         passed inside the variable "a"
    b, //currentValue , for ex currentValue is {x:1} in 1st callback
    currentIndex,
    array
  ) {
    return a.x + b.x; 
  },
  accumulator // this is returned at the end of arr.reduce call 
    //accumulator = returned value i.e return a.x + b.x  in each callback. 
);

during each index callback, value of variable "accumulator" is
passed into "a" parameter in the callback function. If we don't initialize "accumulator", its value will be undefined. Calling undefined.x would give you error.

To solve this, initialize "accumulator" with value 0 as Casey's answer showed above.

To understand the in-outs of "reduce" function, I would suggest you look at the source code of this function.
Lodash library has reduce function which works exactly same as "reduce" function in ES6.

Here is the link :
reduce source code

能怎样 2024-11-09 08:55:51

你不应该使用 ax 作为累加器,而是可以这样做
`arr = [{x:1},{x:2},{x:4}]

arr.reduce(function(a,b){a + bx},0)`

you should not use a.x for accumulator , Instead you can do like this
`arr = [{x:1},{x:2},{x:4}]

arr.reduce(function(a,b){a + b.x},0)`

坏尐絯℡ 2024-11-09 08:55:51

返回所有 x 属性的总和:

arr.reduce(
(a,b) => (a.x || a) + b.x 
)

to return a sum of all x props:

arr.reduce(
(a,b) => (a.x || a) + b.x 
)
云归处 2024-11-09 08:55:51

数组reduce函数需要三个参数,即initialValue(default
它是 0) 、累加器和当前值。
默认情况下,initialValue 的值为 "0" 。这是由
累加器

让我们在代码中看到这一点。

var arr =[1,2,4] ;
arr.reduce((acc,currVal) => acc + currVal ) ; 
// (remember Initialvalue is 0 by default )

//first iteration** : 0 +1 => Now accumulator =1;
//second iteration** : 1 +2 => Now accumulator =3;
//third iteration** : 3 + 4 => Now accumulator = 7;
No more array properties now the loop breaks .
// solution = 7

现在具有初始值的相同示例:

var initialValue = 10;
var arr =[1,2,4] ;
arr.reduce((acc,currVal) => acc + currVal,initialValue ) ; 
/
// (remember Initialvalue is 0 by default but now it's 10 )

//first iteration** : 10 +1 => Now accumulator =11;
//second iteration** : 11 +2 => Now accumulator =13;
//third iteration** : 13 + 4 => Now accumulator = 17;
No more array properties now the loop breaks .
//solution=17

同样适用于对象数组(当前的 stackoverflow 问题):

var arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(acc,currVal){return acc + currVal.x}) 
// destructing {x:1} = currVal;
Now currVal is object which have all the object properties .So now 
currVal.x=>1 
//first iteration** : 0 +1 => Now accumulator =1;
//second iteration** : 1 +2 => Now accumulator =3;
//third iteration** : 3 + 4 => Now accumulator = 7;
No more array properties now the loop breaks 
//solution=7

要记住的一件事是 InitialValue 默认为 0,并且可以给出任何我想要的值:{}、[] 和数字

Array reduce function takes three parameters i.e, initialValue(default
it's 0) , accumulator and current value .
By default the value of initialValue will be "0" . which is taken by
accumulator

Let's see this in code .

var arr =[1,2,4] ;
arr.reduce((acc,currVal) => acc + currVal ) ; 
// (remember Initialvalue is 0 by default )

//first iteration** : 0 +1 => Now accumulator =1;
//second iteration** : 1 +2 => Now accumulator =3;
//third iteration** : 3 + 4 => Now accumulator = 7;
No more array properties now the loop breaks .
// solution = 7

Now same example with initial Value :

var initialValue = 10;
var arr =[1,2,4] ;
arr.reduce((acc,currVal) => acc + currVal,initialValue ) ; 
/
// (remember Initialvalue is 0 by default but now it's 10 )

//first iteration** : 10 +1 => Now accumulator =11;
//second iteration** : 11 +2 => Now accumulator =13;
//third iteration** : 13 + 4 => Now accumulator = 17;
No more array properties now the loop breaks .
//solution=17

Same applies for the object arrays as well(the current stackoverflow question) :

var arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(acc,currVal){return acc + currVal.x}) 
// destructing {x:1} = currVal;
Now currVal is object which have all the object properties .So now 
currVal.x=>1 
//first iteration** : 0 +1 => Now accumulator =1;
//second iteration** : 1 +2 => Now accumulator =3;
//third iteration** : 3 + 4 => Now accumulator = 7;
No more array properties now the loop breaks 
//solution=7

ONE THING TO BARE IN MIND is InitialValue by default is 0 and can be given anything i mean {},[] and number

别把无礼当个性 2024-11-09 08:55:51
    
  
 //fill creates array with n element
 //reduce requires 2 parameter , 3rd parameter as a length
 var fibonacci = (n) => Array(n).fill().reduce((a, b, c) => {
      return a.concat(c < 2 ? c : a[c - 1] + a[c - 2])
  }, [])
  console.log(fibonacci(8))

    
  
 //fill creates array with n element
 //reduce requires 2 parameter , 3rd parameter as a length
 var fibonacci = (n) => Array(n).fill().reduce((a, b, c) => {
      return a.concat(c < 2 ? c : a[c - 1] + a[c - 2])
  }, [])
  console.log(fibonacci(8))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文