preface

For beginners, Reduce is not as friendly as array methods such as Map, forEach, filter, etc. But it has to be said that they can do things, Reduce does not leave behind, called “B god”.

My image of Reduce.

The purpose of this article is to give you a good introduction to reduce how “SAO”.

grammar

Reduce takes two arguments: the first argument is the callback function (mandatory) and the second argument is the initialValue initialValue (optional).

The first argument (the callback function) takes the following four arguments:

  • Accumulator (ACC)
  • Current Value (cur)
  • Current Index (idx)
  • Source Array (SRC)

We usually use the first two parameters in the business, and there are the following two cases.

Browser Support

Image credit: caniuse.com/

No initial value

[1.2.3.4].reduce((acc, cur) = > {
  return acc + cur
})
// 1 + 2 + 3 + 4
/ / 10
Copy the code

With the initial value

[1.2.3.4].reduce((acc, cur) = > {
  return acc + cur
}, 10)
// 10 + 1 + 2 + 3 + 4
/ / 20
Copy the code

⚠️ initialValue initialValue can be of any type. If initialValue is not provided, Reduce executes the callback method starting at index 1, skipping the first index. If initialValue is provided, start at index 0.

It is executed like a snake. Every time the snake eats a bean, the bean will become part of the snake and the snake will eat another bean.

restore

It’s much more than that. It’s like the Pokemon monster, who can become whatever he wants.

reduce -> map

The map method takes a callback function that takes three arguments, the current item, the index, and the original array, and returns a new array with the same length. With these characteristics in mind, we use Reduce to reshape the map.

const testArr = [1.2.3.4]
Array.prototype.reduceMap = function(callback) {
  return this.reduce((acc, cur, index, array) = > {
    const item = callback(cur, index, array)
    acc.push(item)
    return acc
  }, [])
}
testArr.reduceMap((item, index) = > {
  return item + index
})
// [1, 3, 5, 7]
Copy the code

Add the reduceMap method to the Array prototype chain, receive a callback function as the parameter (that is, the callback function passed by map), and get the Array that needs to be operated through this internally. Here, the initial value of the second parameter of the Reduce method is critical. It needs to be set as a [], so as to facilitate the subsequent insertion of the completed item into acc. We need to pass three values to the callback method, the current item, index, and the original array, which is what the native Map callback would get. Return item stuffed into ACC, and return ACC as acc for the next loop (snake principle). Eventually this.reduce returns a new array with the same length.

reduce -> forEach

ForEach takes a callback function as an argument. The function takes four arguments, the current item, the index, the original function, and when executing the callback function, the value of this, and does not return a value.

const testArr = [1.2.3.4]
Array.prototype.reduceForEach = function(callback) {
  this.reduce((acc, cur, index, array) = > {
    callback(cur, index, array)
  }, [])
}

testArr.reduceForEach((item, index, array) = > {
  console.log(item, index)
})
/ / 1234
/ / 0123
Copy the code

As long as you understand reduce -> map, moving to forEach is just a matter of changing the structure.

reduce -> filter

Filter also receives a callback function that returns the current item if it returns true, or not otherwise. The callback function takes the same arguments as forEach.

const testArr = [1.2.3.4]
Array.prototype.reduceFilter = function (callback) {
   return this.reduce((acc, cur, index, array) = > {
    if (callback(cur, index, array)) {
      acc.push(cur)
    }
    return acc
  }, [])
}
testArr.reduceFilter(item= > item % 2= =0) // Filter out even numbers.
/ / (2, 4]
Copy the code

The Boolean type returned by the callback method is Boolean, so if is used to determine whether to insert acc and return ACC for the next comparison. The entire filtered array is returned.

reduce -> find

The callback in the find method also returns a Boolean, which returns the first item that you’re looking for.

const testArr = [1.2.3.4]
const testObj = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
Array.prototype.reduceFind = function (callback) {
  return this.reduce((acc, cur, index, array) = > {
    if (callback(cur, index, array)) {
      if (acc instanceof Array && acc.length == 0) {
      	acc = cur
      }
    }
    // If acc is still an array and its length is 0, then acc = undefined
    if ((index == array.length - 1) && acc instanceof Array && acc.length == 0) {
      acc = undefined
    }
    return acc
  }, [])
}
testArr.reduceFind(item= > item % 2= =0) / / 2
testObj.reduceFind(item= > item.a % 2= =0) // {a: 2}
testObj.reduceFind(item= > item.a % 9= =0) // undefined

Copy the code

You don’t know if the array is an object array or a normal array, so you just override the acc value, and if you find the first value that meets the criteria, you don’t assign any more.

And so on and so on, and you can practice this on your own, just as you’re getting familiar with the Array method again.

derivative

You may not use Reduce very often in your business because you don’t understand it well. In many business scenarios, you accomplish your requirements with more cumbersome and redundant code. Let’s take a look at some of the problems we can solve with Reduce.

Convert a two-dimensional array to a one-dimensional array

const testArr = [[1.2], [3.4], [5.6]]
testArr.reduce((acc, cur) = > {
  return acc.concat(cur)
}, [])
/ / [6]
Copy the code

Count the number of occurrences of each element in the array

const testArr = [1.3.4.1.3.2.9.8.5.3.2.0.12.10]
testArr.reduce((acc, cur) = > {
  if(! (curin acc)) {
    acc[cur] = 1
  } else {
    acc[cur] += 1
  }
  return acc
}, {})

/ / {0, 1, 1, 2, 2, 2, 3, 3, 4:1, 5:1, 8:1, 9:1, 10:1, 12:1}
Copy the code

Note here that I initialized the value to become {}, this requirement requires the form of key value pair, using cur in ACC to determine whether the accumulator acc contains a cur attribute, if there is no default value of 1, if there is already += 1 accumulated once. In real business development, this approach is very common and has many variations. For example, you are given a list of bills (items with the same type of spending), and you are asked to calculate the spending of each type of spending in the list, such as shopping, studying, transferring money, etc. So this is the way to do it, by categorizing.

Categorize arrays by attributes

What we mean by categorizing an array by property, we’re just going to give you a basis, and we’re going to merge the ones that fit. Take the bill for example again, namely by each type of consumption category.

const bills = [
  { type: 'shop'.momey: 223 },
  { type: 'study'.momey: 341 },
  { type: 'shop'.momey: 821 },
  { type: 'transfer'.momey: 821 },
  { type: 'study'.momey: 821}]; bills.reduce((acc, cur) = > {
  // If the key does not exist, set it to an empty array
  if(! acc[cur.type]) { acc[cur.type] = []; } acc[cur.type].push(cur)return acc
}, {})
Copy the code

Array to heavy

I’m not going to explain this, I’m just going to code it.

const testArr = [1.2.2.3.4.4.5.5.5.6.7]
testArr.reduce((acc, cur) = > {
  if(! (acc.includes(cur))) { acc.push(cur) }return acc
}, [])
// [1, 2, 3, 4, 5, 6, 7]
Copy the code

The above code logic is to compare one by one and check whether the current item is already in the accumulator through the includes method.

Find a maximum or minimum value

In an array of objects, I want to get the largest or smallest item of a particular property in an item.

const testArr = [
  { age: 20 },
  { age: 21 },
  { age: 22 }
]
testArr.reduce((acc, cur) = > {
  if(! acc) { acc = curreturn acc
  }
  if (acc.age < cur.age) {
    acc = cur
    return acc
  }
  return acc
}, 0)
// {age: 22}
Copy the code

At the first time, the value of CUR is directly assigned to ACC without comparison, and then the comparison judgment is entered. If the AGE attribute of ACC is less than that of CUR, acc is remade. Acc is returned by default.

conclusion

There are many other scenarios where Reduce can be used, but when you’re dealing with complex operations on arrays, that’s where it comes into play. It will be of great help to you in future business development and interview.