Detailed explanation of reduce fold unfold usage in JS

Detailed explanation of reduce fold unfold usage in JS

fold (reduce)

Let’s talk about reduce. I really like this function. It saves a lot of code and has some declarative prototypes. Some common tool functions, such as flatten, deepCopy, mergeDeep, etc., are implemented elegantly and concisely using reduce. Reduce is also called fold. It is essentially a process of folding an array. It converts multiple values ​​in the array into one value through calculation. Each calculation will be processed by a function. This function is the core element of reduce, called reducer. The reducer function is a two-dimensional function that returns a single value. The common add function is reducer.

const addReducer = (x, y) => x + y;

The add function is a reducer. The most common usage is to use it in conjunction with the array's reduce method.

[1, 2, 3, 4, 5].reduce(addReducer, 0) // 15

To better understand reduce, let's implement this function using different ideas.

Using for...of

const reduce = (f, init, arr) => {
  let acc = init;
  for (const item of arr) {
    acc = f(acc, item);
  }
  return acc
}
// Execute reduceFor(addReducer, 0, [1, 2, 3, 4, 5]) // 15

Using while loop

reduce = (f, init, arr) => {
  let acc = init;
  let current;
  let i = 0;
  while ((current = arr[i++])) {
    acc = f(acc, current);
  }
  return acc;
}

// Execute reduceFor(addReducer, 0, [1, 2, 3, 4, 5]) // 15

More like fold implementation

The above implementation is easy to understand, but it does not seem to reflect the folding process. Folding should be a layer-by-layer squeezing operation on the array. The above implementation actually separates the array and logic, and also introduces more intermediate variables, although there are no side effects internally.
In fact, if you think about it from another perspective, if you pass the state through parameters, you can better reflect the fold process. The parameters here are values ​​that refer to gradually changing arrays and calculated values, and you can make it as stateless as possible. The implementation of a truly pure function has no expressions, only statements, which can be achieved with recursion. The following implementation uses tail recursion to implement reduce. You can see how the array and calculated values ​​change during the implementation process. It fits the name fold very well

function reduce(f, init, arr) {
  if (arr.length === 0) return init;
  const [head, ...rest] = arr;
  return reduceRecursion(f, f(init, head), rest);
}

// Execute reduceFor(addReducer, 0, [1, 2, 3, 4, 5]) // 15

unfold

The reverse of fold is unfold. As the name suggests, unfold generates a series of values ​​based on a reverse reducer. At this point, if the original reducer implementation is similar to (a, b) -> c, then the reverse is c -> [a, b]. Generating a sequence is a very basic operation, but even this basic operation has many implementation ideas. Before introducing unfold, let's take a look at other ways to implement sequences and then make a comparison.

Sequence Implementation

range(0, 100, 5)

Expected results

[0, 5, 10, ... 95]

Array Implementation

I won’t say much about this, everyone should know it.

range = (first, last, step) => {
  const n = (last - first) / step + 1;
  return Array.from({ length: n - 1 })
            .map((_, index) => first + index * step);
}
// You can also use the second parameter of from // Array.from({ length: n }, (_, i) => first + i * step);

Generator Implementation

There is another powerful tool for generating sequences, that is generator, which is used to generate data. The generator returns an iterator, which can also easily generate sequences

function* range(first, last, step) {
  let acc = first;
  while (acc < last) {
    yield acc;
    acc = acc + step;
  }
}
[...range(0, 100, 5)]

Compared with the two, generator focuses more on the generation process, while Array focuses on the data change process.

unfold implementation

Before implementing unfold, let's first sort out the implementation ideas. Like fold, it also uses recursion, and the corresponding data changes must be seen during the implementation process. The general process is as follows

0 -> [0, 5]

5 -> [5, 10]

10 -> [10, 15]

15 -> [15, 20]

...

90 -> [90, 95]

95 -> [95, 100]

It can be seen that the process is exactly the reverse of fold, which conforms to c -> [a, b]. Because the initial value must be an array, unfold only needs two parameters, which is implemented as follows.

function unfold(f, init) {
  const g = (f, next, acc) => {
    const result = f(next);
    const [head, last] = result || [];
    console.log(last);
    return result ? g(f, last, acc.concat(head)) : acc;
  };
  return g(f, init, []);
}

range = R.curry((first, last, step) =>
  unfold(next => next < last && [next, next + step], 0)
)

// Execute range(0, 100, 5)

Summarize

The above is a brief introduction to fold and unfold, two very important concepts in FP programming, combined with reduce and an example of generating a sequence. Of course, their functions are not only to generate sequences, but also have many powerful functions.

The above is a detailed explanation of the usage of reduce fold unfold in JS. For more information about JS, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Summary of using the reduce() method in JS
  • js uses the reduce method to make your code more elegant
  • JavaScript array reduce() method syntax and example analysis
  • Basic use of javascript array includes and reduce
  • Detailed explanation of the differences between js array find, some, filter, and reduce
  • 25 advanced uses of JS array reduce that you must know
  • JS uses the reduce() method to process tree structure data
  • Detailed explanation of JavaScript Reduce
  • Detailed explanation of JavaScript Array.reduce source code
  • 8 JS reduce usage examples and reduce operation methods

<<:  How to check whether the graphics driver has been successfully installed in Ubuntu

>>:  Tutorial on migrating mysql from phpstudy to Linux

Recommend

Some issues we should pay attention to when designing a web page

Web design, according to personal preferences and ...

React implements dynamic pop-up window component

When we write some UI components, if we don't...

Analysis of HTTP interface testing process based on postman

I accidentally discovered a great artificial inte...

jQuery realizes the sliding effect of drop-down menu

When we make a web page, sometimes we want to hav...

Docker installs ClickHouse and initializes data testing

Clickhouse Introduction ClickHouse is a column-or...

A brief discussion on the implementation of fuzzy query using wildcards in MySQL

In the MySQL database, when we need fuzzy query, ...

How to change the Ali source in Ubuntu 20.04

Note that this article does not simply teach you ...

CentOS 7 Forgot Password Solution Process Diagram

need Whether it is a Windows system or a Linux sy...

Idea configures tomcat to start a web project graphic tutorial

Configure tomcat 1. Click run configuration 2. Se...

Database SQL statement optimization

Why optimize: With the launch of the actual proje...

A simple way to implement Vue's drag screenshot function

Drag the mouse to take a screenshot of the page (...

Detailed explanation of MySQL group sorting to find the top N

MySQL group sorting to find the top N Table Struc...

Example of how to reference environment variables in Docker Compose

In a project, you often need to use environment v...