JS high-order function reduce usage

reduceIt is one of the higher-order functions of JavaScript arrays, which is used to perform accumulation operations on the elements in the array, and finally returns an accumulation result. reduceAccepts as an argument a callback function that is executed on each iteration and accepts four arguments: the accumulated value (also known as the accumulator), the current element value, the current index, and the original array.

grammar:

array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)

in:

  • callback: Indicates the callback function, which executes the accumulation logic of the array elements.
  • accumulator: Indicates the cumulative value, which is the result of the cumulative calculation every time the callback function is executed. If provided initialValue, the cumulative value will initialValuestart at ; otherwise, it will start at the first element of the array.
  • currentValue: Indicates the value of the current element.
  • currentIndex: Indicates the index of the current element (optional).
  • array: Represents a primitive array (optional).
  • initialValue: Indicates the initial value of the accumulated value (optional).

Examples of common problem-solving scenarios:

  1. Array summation :
const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);

console.log(sum); // Output: 15
  1. Array averaging :
const numbers = [10, 20, 30, 40, 50];
const average = numbers.reduce((accumulator, currentValue, currentIndex, array) => {
  accumulator += currentValue;
  if (currentIndex === array.length - 1) {
    return accumulator / array.length;
  } else {
    return accumulator;
  }
}, 0);
console.log(average); // Output: 30
  1. Maximum and minimum values ​​in an array :
const numbers = [8, 3, 11, 6, 21, 4];
const max = numbers.reduce((accumulator, currentValue) => Math.max(accumulator, currentValue), numbers[0]);
const min = numbers.reduce((accumulator, currentValue) => Math.min(accumulator, currentValue), numbers[0]);

console.log(max); // Output: 21
console.log(min); // Output: 3
  1. Array element count :
const fruits = ['apple', 'banana', 'orange', 'apple', 'banana', 'apple'];
const count = fruits.reduce((accumulator, currentValue) => {
  accumulator[currentValue] = (accumulator[currentValue] || 0) + 1;
  return accumulator;
}, {});

console.log(count); // Output: { apple: 3, banana: 2, orange: 1 }
  1. The number of occurrences of a character in a string :
const str = "hello world";
const charCount = str.split('').reduce((accumulator, currentValue) => {
  accumulator[currentValue] = (accumulator[currentValue] || 0) + 1;
  return accumulator;
}, {});

console.log(charCount); // Output: { h: 1, e: 1, l: 3, o: 2, ' ': 1, w: 1, r: 1, d: 1 }
  1. Sum object properties :

Suppose there is an array containing product information, and each product object has pricea property. Now we want to calculate the sum of all item prices:

const products = [
  { name: 'Product A', price: 100 },
  { name: 'Product B', price: 200 },
  { name: 'Product C', price: 150 },
];

const total = products.reduce((accumulator, product) => accumulator + product.price, 0);
console.log(total); // Output: 450
  1. Array flattening :

Suppose we have a multidimensional array and we want to flatten it into a one-dimensional array:

const nestedArray = [[1, 2], [3, 4], [5, 6]];
const flattenedArray = nestedArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
console.log(flattenedArray); // Output: [1, 2, 3, 4, 5, 6]
  1. Data classification :

Suppose we have an array containing information about people, each person object has agea property, and now we want to classify people according to their age:

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 25 },
  { name: 'Dave', age: 35 },
];

const peopleByAge = people.reduce((accumulator, person) => {
  const age = person.age;
  if (!accumulator[age]) {
    accumulator[age] = [];
  }
  accumulator[age].push(person);
  return accumulator;
}, {});

console.log(peopleByAge);
/* Output:
{
  25: [
    { name: 'Alice', age: 25 },
    { name: 'Charlie', age: 25 }
  ],
  30: [
    { name: 'Bob', age: 30 }
  ],
  35: [
    { name: 'Dave', age: 35 }
  ]
}
*/
  1. Array deduplication :

reduceDeduplicate the array by :

const numbers = [1, 2, 3, 2, 4, 1, 5, 3, 6];
const uniqueNumbers = numbers.reduce((accumulator, currentValue) => {
  if (!accumulator.includes(currentValue)) {
    accumulator.push(currentValue);
  }
  return accumulator;
}, []);

console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5, 6]
  1. Function Piping :
const data = [1, 2, 3, 4, 5];

const addOne = num => num + 1;
const double = num => num * 2;
const subtractFive = num => num - 5;

const result = data.reduce((accumulator, currentValue) => {
  return [addOne, double, subtractFive].reduce((acc, fn) => fn(acc), currentValue);
}, 0);

console.log(result); // Output: 3 (先加一,再乘以2,再减去5)
  1. Multi-condition data classification :

Suppose there is an array containing personnel information, and each personnel object has ageand genderattributes. Now we want to do multi-criteria classification based on people's age and gender:

const people = [
  { name: 'Alice', age: 25, gender: 'female' },
  { name: 'Bob', age: 30, gender: 'male' },
  { name: 'Charlie', age: 25, gender: 'male' },
  { name: 'Dave', age: 35, gender: 'male' },
  { name: 'Eve', age: 25, gender: 'female' },
];

const peopleByAgeAndGender = people.reduce((accumulator, person) => {
  const { age, gender } = person;
  if (!accumulator[age]) {
    accumulator[age] = {};
  }
  if (!accumulator[age][gender]) {
    accumulator[age][gender] = [];
  }
  accumulator[age][gender].push(person);
  return accumulator;
}, {});

console.log(peopleByAgeAndGender);
/* Output:
{
  25: {
    female: [
      { name: 'Alice', age: 25, gender: 'female' },
      { name: 'Eve', age: 25, gender: 'female' }
    ],
    male: [
      { name: 'Charlie', age: 25, gender: 'male' }
    ]
  },
  30: {
    male: [
      { name: 'Bob', age: 30, gender: 'male' }
    ]
  },
  35: {
    male: [
      { name: 'Dave', age: 35, gender: 'male' }
    ]
  }
}
*/
  1. Array chunking :

Suppose we have a sorted array and we want to chunk it into subarrays of a specified size:

const sortedArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const chunkSize = 3;
const chunkedArray = sortedArray.reduce((accumulator, currentValue, currentIndex) => {
  const chunkIndex = Math.floor(currentIndex / chunkSize);
  if (!accumulator[chunkIndex]) {
    accumulator[chunkIndex] = [];
  }
  accumulator[chunkIndex].push(currentValue);
  return accumulator;
}, []);

console.log(chunkedArray);
/* Output:
[
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
  [10]
]
*/
  1. Array grouping :

Suppose we have an array and we want to group the array according to some condition:

const numbers = [10, 20, 35, 45, 55, 60, 70];

const groups = numbers.reduce((accumulator, currentValue) => {
  const groupKey = currentValue >= 50 ? 'greaterThan50' : 'lessThan50';
  if (!accumulator[groupKey]) {
    accumulator[groupKey] = [];
  }
  accumulator[groupKey].push(currentValue);
  return accumulator;
}, {});

console.log(groups);
/* Output:
{
  greaterThan50: [55, 60, 70],
  lessThan50: [10, 20, 35, 45]
}
*/

When combined with other advanced usages, reduceit can be applied to very complex scenarios. One of the very complex scenarios is implementing function composition or pipelines.

Function composition is a technique for combining multiple functions into a new function, where the output of each function is the input for the next function. We can use reduceand function composition techniques to implement function pipelines, applying a series of functions to data and passing the results in turn.

Function pipeline example :

Suppose we have an array of strings that we want to convert to uppercase, strip spaces and concatenate them into a single word:

const words = ['  hello', 'world ', 'JavaScript '];

const compose = (...functions) => input => functions.reduceRight((acc, fn) => fn(acc), input);

const toUpperCase = str => str.toUpperCase();
const trim = str => str.trim();
const concatenate = (str1, str2) => str1 + str2;

const result = words.map(compose(trim, toUpperCase)).reduce(concatenate);
console.log(result); // Output: "HELLOWORLDJAVASCRIPT"

In the above example, we first defined three simple string processing functions: toUpperCase(convert a string to uppercase), trim(remove spaces at both ends of a string), and concatenate(join two strings together). We then define a composefunction that takes any number of functions and returns a new function that in turn applies the passed in functions to the input data. In composethe function, we use reduceRightto apply the functions sequentially, which ensures that the functions are executed in right-to-left order.

Then, we use mapthe method to wordspass each string in the array to composethe function in turn, and then use reducethe method to splice the converted results together to get the final result: "HELLOWORLDJAVASCRIPT".

This example shows how to combine function composition and reduceimplement a complex function pipeline. In this way, you can handle more complex data conversion and processing tasks in actual development.

Another complex scenario is to use reduceand recursion to implement tree structure operations. Such scenarios are very useful when dealing with hierarchical data, such as tree-structured JSON data or nested arrays of objects.

Example of tree structure operation :

Suppose there is a JSON data containing a tree structure, each node has idand childrenattributes. We want to implement the function of finding nodes reduceaccording to :id

const treeData = {
  id: 1,
  children: [
    {
      id: 2,
      children: [
        {
          id: 3,
          children: []
        },
        {
          id: 4,
          children: []
        }
      ]
    },
    {
      id: 5,
      children: []
    }
  ]
};

const findNodeById = (tree, id) => {
  return tree.id === id
    ? tree
    : tree.children.reduce((acc, child) => acc || findNodeById(child, id), null);
};

const foundNode = findNodeById(treeData, 3);
console.log(foundNode); // Output: { id: 3, children: [] }

In the above example, we first defined a findNodeByIdfunction that reducerecursively traverses the tree structure using . It compares the passed in idwith the current node's , and if it matches, it returns the current node; otherwise, it continues recursively traversing the node's children until it finds a matching node or traverses the entire tree.id

In this way, we can use reduceand recursion to implement complex tree structure operations, such as idfinding nodes according to , calculating the depth of nodes or breadth-first traversal, etc.

reduceCan be very useful in examples dealing with tree structures. In a tree structure, each node may have child nodes, forming a hierarchy. Use reducecan implement recursive traversal, search, conversion and other operations in the tree structure. Here is an example of using in a tree structure reduce:

Assume that the following tree structure data represents the directory structure of the file system:

const fileSystem = {
  name: 'root',
  type: 'folder',
  children: [
    {
      name: 'folder1',
      type: 'folder',
      children: [
        {
          name: 'file1.txt',
          type: 'file',
        },
        {
          name: 'file2.txt',
          type: 'file',
        },
      ],
    },
    {
      name: 'folder2',
      type: 'folder',
      children: [
        {
          name: 'file3.txt',
          type: 'file',
        },
      ],
    },
  ],
};
  1. Count the number of files :

We can reducecount the number of files recursively in the tree structure using:

const countFiles = (node) => {
  if (node.type === 'file') {
    return 1;
  } else if (node.type === 'folder') {
    return node.children.reduce((acc, child) => acc + countFiles(child), 0);
  } else {
    return 0;
  }
};

const totalFiles = countFiles(fileSystem);
console.log(totalFiles); // Output: 3
  1. Get the specified file path :

We can use to reducerecursively find the specified file path in the tree structure:

const findFileByPath = (node, path) => {
  if (node.name === path) {
    return node;
  } else if (node.type === 'folder') {
    for (const child of node.children) {
      const foundFile = findFileByPath(child, path);
      if (foundFile) {
        return foundFile;
      }
    }
  }
  return null;
};

const filePath = 'file3.txt';
const foundFile = findFileByPath(fileSystem, filePath);
console.log(foundFile); // Output: { name: 'file3.txt', type: 'file' }
  1. Convert tree structure :

We can reducetransform node data recursively in a tree structure using:

const transformTree = (node) => {
  if (node.type === 'file') {
    return { file: node.name };
  } else if (node.type === 'folder') {
    return {
      folder: node.name,
      children: node.children.reduce((acc, child) => [...acc, transformTree(child)], []),
    };
  } else {
    return null;
  }
};

const transformedTree = transformTree(fileSystem);
console.log(transformedTree);
/* Output:
{
  folder: 'root',
  children: [
    {
      folder: 'folder1',
      children: [
        { file: 'file1.txt' },
        { file: 'file2.txt' }
      ]
    },
    {
      folder: 'folder2',
      children: [
        { file: 'file3.txt' }
      ]
    }
  ]
}
*/

Guess you like

Origin blog.csdn.net/qq_20173195/article/details/131828794