# The meaning of Reduce and Transduce

To learn functional programming , you must master a lot of terms, otherwise you won’t understand the documentation at all.

This article introduces two basic terms: reduce and transduce . They are very important and very useful.

## 1. The usage of reduce

reduce It is an array operation, usually used to “accumulate” all the members of an array into one value.

var arr = [1, 2, 3, 4];

var sum = (a, b) => a + b;

arr.reduce(sum, 0) // 10

In the above code, a function is executed on each member reduce of the array . The parameter is a cumulative variable, and the parameter is the current array member. Each time it is executed, it will be added to and finally output . arr sum sum a b b a a

The cumulative variable must have an initial value. The above example is reduce the second parameter of the function 0 . If this parameter is omitted, the initial value defaults to the first member of the array.

var arr = [1, 2, 3, 4];

var sum = function (a, b) {
console.log(a, b);
return a + b;
};

arr.reduce(sum) // => 10
// 1 2
// 3 3
// 6 4

In the above code, the reduce method omits the initial value. Through sum the print statement in the function, you can see every change of the accumulated variable.

In short, the reduce method provides a traversal means to “accumulate” all members of the array.

## 2. Map is a special case of reduce

The initial value of the cumulative variable can also be an array.

var arr = [1, 2, 3, 4];

var handler = function (newArr, x) {
newArr.push(x + 1);
return newArr;
};

arr.reduce(handler, [])
// [2, 3, 4, 5]

In the above code, the initial value of the cumulative variable is an empty array, and reduce a new array is returned as a result , which is equivalent to the execution map method, which “transforms” the original array once. The following is map an example of using rewrite the above.

var arr = [1, 2, 3, 4];
var plusOne = x => x + 1;
arr.map(plusOne) // [2, 3, 4, 5]

In fact, all map methods can be based on reduce implementation.

function map(f, arr) {
return arr.reduce(function(result, x) {
result.push(f(x));
return result;
}, []);
}

Therefore, it map is just reduce a special case.

## Three, reduce the essence

Essentially, it reduce is a combination of three operations.

• Traverse
• Deformed
• accumulation

Let’s look at the example above.

var arr = [1, 2, 3, 4];
var handler = function (newArr, x) {
newArr.push(x + 1);
return newArr;
};

arr.reduce(handler, [])
// [2, 3, 4, 5]

In the above code, first, reduce the original array is traversed, which is map the fundamental reason why it can replace the method; second, reduce each member of the original array is “transformed” (addition in the above example 1 ); finally, they are accumulated (The above example is the push method).

## Fourth, the meaning of transduce

reduce Contains three operations, so it is very useful. But it also brings a problem: the reusability of the code is not high. In the reduce inside, the deformation and accumulation are coupled, not easy to split.

For each use reduce , developers often have to write code from scratch and repeatedly implement many basic functions. It is difficult to reuse other people’s code.

var handler = function (newArr, x) {
newArr.push(x + 1);
return newArr;
};

The above processing function is difficult to use in other situations.

Is there a solution? The answer is yes, that is, to separate the two operations of “deformation” and “accumulation”. If the reduce transformation operation and accumulation operation are allowed to be separated, the reusability of the code will be greatly increased. This is transduce the origin of the method.

transduce The name comes from the combination of the two words transform and reduce. It is actually reduce a less coupled way of writing methods.

// 变形运算
var plusOne = x => x + 1;

// 累积运算
var append = function (newArr, x) {
newArr.push(x);
return newArr;
};

R.transduce(R.map(plusOne), append, [], arr);
// [2, 3, 4, 5]

In the above code, it plusOne is a deformation operation and append an accumulation operation. I used Ramda library ‘s transduce implementation. It can be seen transduce that the deformation and accumulation are reduce separated, and the others are no different.

## Five, the usage of transduce

transduce The biggest advantage is that code reuse is easier.

var arr = [1, 2, 3, 4];
var append = function (newArr, x) {
newArr.push(x);
return newArr;
};

// 示例一
var plusOne = x => x + 1;
var square = x => x * x;

R.transduce(
R.map(R.pipe(plusOne, square)),
append,
[],
arr
); // [4, 9, 16, 25]

// 示例二
var isOdd = x => x % 2 === 1;

R.transduce(
R.pipe(R.filter(isOdd), R.map(square)),
append,
[],
arr
); // [1, 9]

In the above code, the first example is the combination of two deformation operations, and the second example is the combination of the filtering operation and the deformation operation. Both of these examples use the Pointfree style .

It can be seen that it transduce is very conducive to code reuse, and a series of simple and reusable functions can be synthesized into complex operations. As an exercise, interested readers can try and use the reduce method to complete the above two examples. You will find that the complexity and number of lines of the code has increased greatly.

## Six, Transformer object

transduce The first parameter of the function is an object, called a Transformer object (deformer). In the previous example, R.map(plusOne) what is returned is a Transformer object.

In fact, any object as long as it conforms to the Transformer protocol is a Transformer object.

var Map = function(f, xf) {
return {
"@@transducer/init": function() {
return xf["@@transducer/init"]();
},
"@@transducer/result": function(result) {
return xf["@@transducer/result"](result);
},
"@@transducer/step": function(result, input) {
return xf["@@transducer/step"](result, f(input));
}
};
};

In the above code, the Map function returns a Transformer object. It must have the following three attributes.

• @@transducer/step: Perform transformation operations
• @@transducer/result: return the final value after transformation

All objects conforming to this protocol can be combined with other Transformer objects and serve as transduce the first parameter of the function.

Therefore, transduce the parameter types of the function are as follows.

transduce(
变形器 : Object,
累积器 : Function,
初始值 : Any,
原始数组 : Array
)

## Seven, into method

Finally, you may find that all the previous examples use the same accumulator.

var append = function (newArr, x) {
newArr.push(x);
return newArr;
};

The append function of the above code is a common accumulator. Therefore, the Ramda function library provides a into way to build it. In other words, the into method is equivalent to append the transduce function provided by default .

// 等同于

In the above code, into the first parameter of the method is the initial value, the second parameter is the deformer, and the third parameter is the original array. There is no need to provide an accumulator.

Here is another example.

R.into(
[5, 6],