欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

阵列缩小法的深度应用

最编程 2024-03-15 21:11:30
...

1.reduce方法介绍

reduce()  方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值

  • 一个 “reducer” 函数,包含四个参数:

    • previousValue:上一次调用 callbackFn 时的返回值。在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,否则为数组索引为 0 的元素 array[0]
    • currentValue:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
    • currentIndex:数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。
    • array:用于遍历的数组。
  • initialValue 可选

    作为第一次调用 callback 函数时参数 previousValue 的值。若指定了初始值 initialValue,则 currentValue 则将使用数组第一个元素;否则 previousValue 将使用数组第一个元素,而 currentValue 将使用数组第二个元素。

返回值

使用 “reducer” 回调函数遍历整个数组后的结果

2.使用reduce方法的好处

reduce方法内部使用了迭代器,可以解决一些递归类的问题,日常开发中可以使用它解决非常复杂的嵌套对象,例如:在处理大量嵌套数据(如 JSON 文件)时,javascript 中很少有基本的数组方法会被重复使用,可以单独使用 reduce 以用更少的代码实现相同的结果。

3.reduce方法的实际应用

3.1.记录数组中元素的次数

场景描述:

需要根据数组当中存在的值,去记录每次值出现的次数 arr=[1,2,3,4,5,1,2,3],那么结果就是[{1:2},{2:2},{3;2},{4:1},{5:1}]

解决思路:

判断查找当前元素是不是在数组中已经存在过了,如果不存在,那么它就是第一次出现,记录一下该元素已经存在一次了,如果存在就在之前记录的次数上加一.

      function totalNum(arr) {
        const newArr = arr.reduce((pre, cur) => {
          if (!pre[cur]) {
            pre[cur] = 1;
          } else {
            pre[cur]++;
          }
          return pre;
        }, {});
        return newArr;
      }

3.2.解决对象数组的去重问题

场景描述:

一般数组去重可以用对象唯一键值的方式,根据object和set的属性名不能重复来判断,但是对象数组就没法判断

解决思路

使用空对象进行存储,从数组中取出对象元素跟目标对象元素进行比对,如果没有,就将当前对象元素push进当前的数组中,否则目标对象中有,则返回空

  function  unbalance(arr) {
        let obj = Object.create(null);
        let newArr = arr.reduce((pre, cur) => {
          obj[cur.name] ? "" : (obj[cur.name] = 1 && pre.push(cur));
          return pre;
        }, []);
        return newArr;
      }

3.3.计算年龄

场景描述

有一个年龄数组,它代表人们出生的年份,我们只想保留18岁以上的人,并计算出人们的年龄

const years = [1997, 1999, 2001201220172020];
const currentYear = (new Date).getFullYear();
const reducer = (accumulator, year) => {
  const age = currentYear - year;
  if (age < 18) {
    return accumulator;
  }

  accumulator.push({
    year,
    age
  });

  return accumulator;
}

const over18Ages = years.reduce(reducer, []);

3.4.树的数据处理

需求分析

在封装树组件的时候,经过后端返回数据,我们需要将数据加工成我们所需要的数据,将扁平化的数据做嵌套处理,如果不使用递归,就可以通过reduce实现

需要处理的数据

  {"code":0,"parent":[{"name":"文件夹1","pid":0,"id":1},{"name":"文件夹2","pid":0,"id":2},
  {"name":"文件夹3","pid":0,"id":3},{"name":"文件夹1-1","pid":1,"id":4},{"name":"文件夹2-
  1","pid":2,"id":5}],"child":[{"name":"文件1","pid":1,"id":1001},{"name":"文件
  2","pid":1,"id":1002},{"name":"文件2-1","pid":2,"id":1003},{"name":"文件2-
  2","pid":2,"id":1004},{"name":"文件1-1","pid":4,"id":1005},{"name":"文件2-1-1","pid":5,"id":1006}]}

处理后的数据

[{"name":"文件夹1","pid":0,"id":1,"children":[{"name":"文件夹1-1","pid":1,"id":4,"children":
[{"name":"文件1-1","pid":4,"id":1005}]},{"name":"文件1","pid":1,"id":1001},{"name":"文件
2","pid":1,"id":1002}]},{"name":"文件夹2","pid":0,"id":2,"children":[{"name":"文件夹2-
1","pid":2,"id":5,"children":[{"name":"文件2-1-1","pid":5,"id":1006}]},{"name":"文件2-
1","pid":2,"id":1003},{"name":"文件2-2","pid":2,"id":1004}]},{"name":"文件夹3","pid":0,"id":3}]
      //1.先扁平化数组
      const allData = [...data.parent, ...data.child];
      //2.做树的映射表,改成以下结构
     //{1:{name:"文件夹1",pid:0,id:1}}
     const treeData = allData.reduce((pre, cur) => {
        pre[cur["id"]] = cur;
        return pre;
      }, {});
      //3.做数据处理
     const newData = allData.reduce((pre, cur) => {
    //从当前项中拿到pid
        let { pid } = cur;
    //根据映射表判断是否有对应的对象
        let parent = treeData[pid];
        if (parent) {
            // debugger
            // console.log( parent.children,' parent.children');
          parent.children
            ? parent.children.push(cur)
            : (parent.children = [cur]);
        } else if (pid ===0) {
          pre.push(cur);
        }
        return pre;
      }, []);

3.5 使用函数实现管道

需求分析

有一堆函数,需要将上一函数的返回值作为下个函数的入参进行计算,实现一个管道函数

      const double = x => x + x;
      const triple = x => 3 * x;
      const quadruple = x => 4 * x;

      const pipe = (...functions) =>initialValue =>functions.reduce((acc, fn) => fn(acc), initialValue);

      const multiply6 = pipe(double, triple);
      const multiply9 = pipe(triple, triple);
      const multiply16 = pipe(quadruple, quadruple);
      const multiply24 = pipe(double, triple, quadruple);

     
      multiply6(6); // 36
      multiply9(9); // 81
      multiply16(16); // 256
      multiply24(10); // 240
      

3.6功能函数集成

需求分析

比如我需要将一个字符串切割成数组,在计算数组的长度,然后根据数组的长度做一系列计算操作

      const toWords = (string) => string.split(" ");
      const count = (array) => array.length;
      const wpm = (wordCount) => wordCount * 30;
      const speed = (string, func) =>func.reduce((composed, fn) => fn(composed), string);
      speed("wo shi wangsu", [toWords, count, wpm]);

3.7 多个请求的先后执行问题

需求分析

多个请求并发操作,b请求需要在a请求得到相应结果之后操作,除了使用async和await外还可以采用erduce+promise的方式

function runPromiseInSequence(arr, input) {
        return arr.reduce(
          (promiseChain, currentFunction) => promiseChain.then(currentFunction),
          Promise.resolve(input)
        );
      }

      function p1(a) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(a * 5);
          }, 1000);
        });
      }
      function p2(a) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(a * 2);
          }, 1000);
        });
      }
      function f3(a) {
        return a * 3;
      }

      function p4(a) {
        return new Promise((resolve, reject) => {
          resolve(a * 4);
        });
      }

      const promiseArr = [p1, p2, f3, p4];
      runPromiseInSequence(promiseArr, 10).then(res=>{
        console.log(res);
      });

3.8使用reduce迭代器解决递归问题

需求分析

递归函数经常被使用,因为它们的语义定义,,如果可以将递归函数转换为迭代方法,就可以使用reducereduce如果做得好,在启用声明性定义的同时,就不会有可能填满函数堆栈的问题。

const factorial = (number) =>
  number === 0 ? 1 : number * factorial(number - 1);
const factorial = (number) =>
  Array(number)
    .fill(number)
    .reduce((acc, elem, i) => acc * (elem - i));

推荐阅读