JavaScript API简介:Reduce函数

As the year begins, I have decided to make a series of articles that explain the various APIs (Application Programming Interfaces) in the JavaScript language. In each article we will break down a commonly used function in JavaScript and try to go through its various applications.

随着一年的开始,我决定撰写一系列文章,以JavaScript语言解释各种API(应用程序编程接口)。 在每篇文章中,我们将分解JavaScript中常用的功能,并尝试遍历其各种应用程序。

The first function we will be going through is the 'Reduce' higher-order function. This is mainly because, out of all the JS array methods, it took me a bit of time to understand how the Reduce function works.

我们将要经历的第一个功能是“ 减少 ”高阶功能。 这主要是因为在所有JS数组方法中,我花了一些时间来了解Reduce函数的工作方式。

This article assumes that the reader understands other array methods like Map and Filter because it will help in understanding how Reduce works.

本文假定读者了解其他数组方法(例如MapFilter),因为它将有助于理解Reduce的工作原理。

In order to fully grasp the idea behind Reduce, we will look at a few examples of simple solutions using for loops and then implement those same solutions using the Reduce function. Then we will look at some more advanced use cases for the Reduce function.

为了完全掌握Reduce的思想我们将看一些使用for循环的简单解决方案的示例,然后使用Reduce来实现相同的解决方案。 功能。 然后,我们将研究Reduce的一些更高级的用例 功能。

例子1 (Example 1)

The first example we will look at is a common one: calculating the sum of items in an array. This requires a simple solution, and using a for loop should look like this:

我们将看到的第一个示例是一个常见示例:计算数组中项的总和。 这需要一个简单的解决方案,并且使用for循环应如下所示:

const arrayItems = [1,2,3,4,5,6];
let sum = 0;

for (let i = 0; i < arrayItems.length; i++) {
	sum = sum + arrayItems[i];
}
// sum = 21

The solution above is pretty straightforward, where we add each item in the array and store the result in the sum variable. So the next step is to implement the same solution using Reduce, which should look like the code below:

上面的解决方案非常简单,我们在数组中添加每个项目并将结果存储在sum变量中。 因此,下一步是使用Reduce实施相同的解决方案, 看起来应该像下面的代码:

const arrayItems = [1,2,3,4,5,6];

const sum = arrayItems.reduce(function(accumulator, currentItemInArray){
	accumulator = accumulator + currentItemInArray;
    return accumulator;
}, 0);

// sum = 21

Looking at the two examples above it's pretty obvious that the for loop example seems simpler, and this has been the cause of some arguments in the ecosystem. But this example is overkill, and we are only using it make it easy to understand how the Reduce function works, so let's work through the example.

查看上面的两个示例,很明显, for循环示例似乎更简单,这是生态系统中某些参数的原因。 但是这个例子太夸张了,我们仅使用它就可以很容易地了解 函数起作用,因此让我们通过示例进行研究。

We need to, first of all, understand what the Reduce function is. It is a method that exists for every JavaScript Array. It enables us to loop through each item in the array and perform a function on each of those items.

首先,我们需要了解什么是Reduce函数。 这是每个JavaScript数组都存在的方法。 它使我们能够遍历数组中的每个项目并对每个项目执行功能。

This is pretty similar to the behavior of the Map function, but it has a twist–it allows us to return any value from our function in a particular iteration, which will then exist as a parameter (argument) in that function in the next iteration (that value is commonly known as the accumulator).

这与Map函数的行为非常相似,但是它有一个扭曲-它允许我们在特定的迭代中返回函数中的任何值,然后在下一次迭代中将其作为参数(自变量)存在(该值通常称为累加器 )。

To explain further, the Reduce function takes 2 arguments:

为了进一步解释,减少 函数采用2个参数:

  • Callback function: This is a function that contains 4 parameters typically. But right now we are only concerned with the first, the accumulator, and the second which is the current item in the array during that iteration.

    回调函数:该函数通常包含4个参数。 但是现在,我们只关心第一个,累加器和第二个,它是该迭代期间数组中的当前项。
  • Initial value: This is the initial value of the accumulator when the iteration starts. In the example above the value is 0, which means the initial value of the accumulator will be 0.

    初始值:这是迭代开始时累加器的初始值。 在上面的示例中,该值为0,这意味着累加器的初始值为0。

Back to our example:

回到我们的例子:

const arrayItems = [1,2,3,4,5,6];

const sum = arrayItems.reduce(function(accumulator, currentItemInArray){
	accumulator = accumulator + currentItemInArray;
    return accumulator;
}, 0);

// sum = 21

It can be further broken out into the callback function and the initial value:

它可以进一步细分为回调函数和初始值:

const arrayItems = [1,2,3,4,5,6];

function callbackFunction(accumulator, currentItemInArray){
    accumulator = accumulator + currentItemInArray;
    return accumulator;
}

const initialValue = 0;

const sum = arrayItems.reduce(callbackFunction, initialValue);

// sum = 21

The tricky part for me was understanding how the accumulator works. To explain it we will go through each iteration in the loop.

对我而言,最棘手的部分是了解蓄电池的工作原理。 为了解释它,我们将遍历循环中的每个迭代。

迭代1 (Iteration 1)

In the first iteration, since our initial value is 0, our accumulator will have a value of 0. So our function will look like this:

在第一次迭代中,由于我们的初始值为0,所以累加器的值为0。因此我们的函数将如下所示:

const arrayItems = [1,2,3,4,5,6];
// 1 is the current item in the array

function callbackFunction(accumulator = 0, currentItemInArray = 1){
    accumulator = 0 + 1;
    return accumulator // which is 1;
}

callbackFunction will return a value of 1. This will automatically be used as the next value for the accumulator in the second iteration.

callbackFunction将返回值1。该值将自动用作第二次迭代中累加器的下一个值。

迭代2 (Iteration 2)

const arrayItems = [1,2,3,4,5,6];
// 2 is the current item in the array

function callbackFunction(accumulator = 1, currentItemInArray = 2){
    accumulator = 1 + 2;
    return accumulator // which is 3;
}

In this iteration, our accumulator will have a value of 1 which was returned in our first iteration. The callbackFunction will return a value of 3 in this iteration. This means that our accumulator will have a value of 3 in our third iteration.

在此迭代中,累加器的值为1,该值在我们的第一次迭代中返回。 callbackFunction在此迭代中将返回值3。 这意味着我们的累加器在第三次迭代中的值为3。

迭代3 (Iteration 3)

const arrayItems = [1,2,3,4,5,6];
// 3 is the current item in the array

function callbackFunction(accumulator = 3, currentItemInArray = 3){
    accumulator = 3 + 3;
    return accumulator // which is 6;
}

In the third iteration, our accumulator will have a value of 3 which was returned by the callbackFunction in iteration 2. The  callbackFunction will return a value of 6, which will be used as the value of accumulator in iteration 4. These steps will repeat themselves until we get to the last item in the array which is 6.

在第三次迭代中,我们的累加器将具有值3,其通过返回callbackFunction在迭代2中callbackFunction将返回值6,这将在迭代4。这些步骤被用作累加器的值将重复自己直到我们到达数组中的最后一项为6。

As I mentioned before, the example above can be an overkill, so let's look at a problem where using Reduce is more common. (However, this doesn't mean that a for loop cannot be used to implement a working solution).

正如我之前提到的,上面的示例可能有点夸张,所以让我们看一下使用Reduce的问题 更常见。 (但是,这并不意味着不能使用for循环来实现有效的解决方案)。

例子2 (Example 2)

The second example will involve counting the number of occurrences of each element in an array, for example:

第二个示例将涉及计算数组中每个元素的出现次数,例如:

//Given an input
const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// should give an output of
const count = { 'apples': 3,'oranges': 2,'bananas': 2, 'grapes': 1 };

Let's implement the solution, then go through each iteration and see what is happening:

让我们实施解决方案,然后遍历每个迭代,看看发生了什么:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

function countOccurrence(accumulator, currentFruit){
	const currentFruitCount = accumulator[currentFruit];
    // if the fruit exists as a key in the  object, increment its value, else add the fruit as a key to the object with a value of 1
    
    if(currentFruitCount) {
    	accumulator[currentFruit] = currentFruitCount + 1;
    } else {
    	accumulator[currentFruit] = 1
    }
    
    return accumulator;
}

const initialValue = {};

const count = fruits.reduce(countOccurrence, initialValue);

The solution is written to be as verbose a possible so we can understand what is going on in the code. As we did before, let's go through the first few iterations.

该解决方案编写得尽可能详尽,因此我们可以了解代码中正在发生的事情。 和以前一样,让我们​​进行前几个迭代。

迭代1 (Iteration 1)

In the first iteration, since we made our initial value an empty object, the value of accumulator will be an empty object. This means that the countOcurrence function will look like the code below when it is called:

在第一次迭代中,由于我们将初始值设为一个空对象,所以accumulator的值将为一个空对象。 这意味着countOcurrence函数在被调用时将类似于以下代码:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'apples'

function countOccurrence(accumulator = {}, currentFruit = 'apples'){
    // since currentFruit = 'apples' then accumulator[currentFruit] = accumulator['apples']
    
	const currentFruitCount = accumulator[currentFruit];
    // currentFruitCount will be null since accumulator is an empty object
    
    if(currentFruitCount) {
    	accumulator[currentFruit] = currentFruitCount + 1;
    } else {
        // this block will run since accumulator is empty
        // currentFruit = 'apples'
    	accumulator['apples'] = 1
        // accumulator should look like this: { 'apples': 1 }
    }
    
    return accumulator // which is { 'apples': 1 };
}

Since accumulator is an empty object, currentFruitCount will be null. This means that the else block will run where a new key (apples) with the value of 1 will be added to the accumulator. This will be returned from the function which will be passed as the value of the accumulator in the second iteration.

由于accumulator是一个空对象,因此currentFruitCount将为null 。 这意味着else块将在其中将值1的新键(苹果)添加到accumulator 。 这将从函数返回,该函数将在第二次迭代中作为累加器的值传递。

迭代2 (Iteration 2)

In the second iteration, our accumulator will have the value of { 'apples': 1 }, which was returned by the countOccurrence function in the first iteration. Then the countOccurrence function will look like the code below:

在第二次迭代中,我们的accumulator将具有{ 'apples': 1 }的值,该值由第一次迭代中的countOccurrence函数返回。 然后countOccurrence函数将类似于以下代码:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'apples'

function countOccurrence(accumulator = { 'apples': 1 }, currentFruit = 'apples'){
    // since currentFruit = 'apples' then accumulator[currentFruit] = accumulator['apples']
    
	const currentFruitCount = accumulator[currentFruit];
    // currentFruitCount will be 1 
    
    if(currentFruitCount) {
        // this block will run since currentFruitCount is 1
        // currentFruit = 'apples'
    	accumulator['apples'] = 1 + 1;
        // accumulator should look like this: { 'apples': 2 }
    } else {
    	accumulator[currentFruit] = 1
    }
    
    return accumulator // which is { 'apples': 2 };
}

Since the accumulator contains a key ('apple') with the value of 1, currentFruit will be 1, which means the if block will be run. In that block the value of the apple key will be incremented by 1 making it 2, and this new value will be updated in the accumulator object to make it { 'apples' : 2 } . This value will be returned by the countOccurrence function and passed as the value for the accumulator in the third iteration.

由于accumulator包含值为1的键(“苹果”), currentFruit将为1,这意味着将运行if块。 在该块中, apple key的值将增加1,使其变为2,并且此新值将在累加器对象中更新为{ 'apples' : 2 } 。 该值将由countOccurrence函数返回,并在第三次迭代中作为累加器的值传递。

迭代3 (Iteration 3)

For our third iteration, accumulator has the value of { apples: 2 } which was returned by countOccurence during the second iteration. The countOccurence function will look like the code below:

对于我们的第三次迭代, accumulator的值为{ apples: 2 } ,该值在第二次迭代期间由countOccurence返回。 countOccurence函数将类似于以下代码:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'bananas'

function countOccurrence(accumulator = { 'apples': 2 }, currentFruit = 'bananas'){
    // since currentFruit = 'bananas' then accumulator[currentFruit] = accumulator['bananas']
    
	const currentFruitCount = accumulator[currentFruit];
        // currentFruitCount will be null since accumulator doesn't contain 'bananas'
    
    if(currentFruitCount) {
        accumulator[currentFruit] = currentFruitCount + 1;
    } else {
        // this block will run since currentFruitCount is null
        // currentFruit = 'bananas'
    	accumulator['bananas'] = 1
    }
    
    return accumulator // which is { 'apples': 2, 'bananas': 1  };
}

This iteration is similar to the first one–since bananas doesn't exist in accumulator it will be added to the object and given a value of 1 , making accumulator look like this: { 'apples': 2, 'bananas': 1 }. This will then become the value of accumulator for the fourth iteration.

此迭代与第一个迭代类似,因为accumulator中不存在bananas ,它将被添加到对象中并赋予值1 ,从而使accumulator如下所示: { 'apples': 2, 'bananas': 1 } 。 然后,它将成为第四次迭代的accumulator值。

The process will repeat itself until the Reduce function has iterated through each element in the array.

该过程将重复进行直到减少 函数已遍历数组中的每个元素。

结语 (Wrapping up)

I really hope these examples were clear enough to create a mental model of how the Reduce function works.

我真的希望这些示例足够清楚,可以为Reduce函数的工作方式创建一个心理模型。

If you are reading this and you would like to see more advanced examples (like implementing the pipe function) feel free to tweet at me and I'll respond as soon as I can. Also, if you have other examples I would love to see them. Thanks!!!

如果您正在阅读本文,并且希望看到更多高级示例(例如实现pipe功能),请随时向我发送推特,我将尽快答复。 另外,如果您还有其他示例,我也很乐意看到它们。 谢谢!!!

翻译自: https://www.freecodecamp.org/news/applications-of-the-reduce-function-in-javascript/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值