前端JS商品规格组合

给定一个数组

   let data = [
      {
        name: "颜色",
        specs: ["白色", "黑色"],
      },
      {
        name: "尺寸",
        specs: ["14寸","15寸", "16寸"],
      },
      {
        name: "处理器",
        specs: ["i5", "i7", "i9"],
      },
    ];

组合处理(据说这套路叫什么啥笛卡尔积)

方法很巧妙,自己写不一定写的出,但是可以借鉴前人的经验,然后去试着理解,分析,即使写不出也要能看的懂,如果完成任务直接拿现成的方法用也无妨

function combine(arr) {
      let result = [[]];//定义一个数组必须要有一项(且这一项必须是数组)
      arr.map((x) => {
        let res = [];
        console.log(result,'result');
        result.map((y) => {
          x.specs.map((z) => {
            //最内层循环x.specs.map第一次执行完之后res的值就是[["白色"], ["黑色"]],因为specs的值为两项["白色", "黑色"]循环两遍,循环完后跳出循环到上一层循环,
            //此时上一层的循环result.map的result还是[[]],所以执行完一遍之后跳出当前循环到上一层循环,
            //此时arr.map循环完第一遍开始赋值将result = res,此时result为[["白色"], ["黑色"]],然后开始进入result.map循环
            //此时x.specs.map的值为arr.map的第二次循环也就是循环["14寸","15寸", "16寸"],而result.map为[["白色"], ["黑色"]],
            //此时循环的步骤为result.map第一遍循环result,此时y为["白色"],而z为arr第二项的specs里面的每一项,于是用["白色"]去拼接["14寸","15寸", "16寸"]的每一项
            //此时就res就变成了result.map[["白色"], ["黑色"]]跟["14寸","15寸", "16寸"]去按顺序一项一项的去组合,组合完之后将 result = res,
            //以此类推便出现了最终的所有值的组合结果,很巧妙的一个套路,自己去从0开始写还是比较费脑筋的,尤其逻辑处理能力尚不强的时候以及没多少经验的时候
            res.push([...y, z]);
          });
        });
        result = res;//将第一次循环之后的值赋值给result,此时result为[["白色"], ["黑色"]],故下一波循环得循环两次
      });
      return result;
    }
    console.log(combine(data));

逻辑解释(给自己看的),配合打印的值看更容易理解

//最内层循环x.specs.map第一次执行完之后res的值就是[["白色"], ["黑色"]],因为specs的值为两项["白色", "黑色"]循环两遍,循环完后跳出循环到上一层循环,

            //此时上一层的循环result.map的result还是[[]],所以执行完一遍之后跳出当前循环到上一层循环,

            //此时arr.map循环完第一遍开始赋值将result = res,此时result为[["白色"], ["黑色"]],然后开始进入result.map循环

            //此时x.specs.map的值为arr.map的第二次循环也就是循环["14寸","15寸", "16寸"],而result.map为[["白色"], ["黑色"]],

            //此时循环的步骤为result.map第一遍循环result,此时y为["白色"],而z为arr第二项的specs里面的每一项,于是用["白色"]去拼接["14寸","15寸", "16寸"]的每一项

            //此时就res就变成了result.map[["白色"], ["黑色"]]跟["14寸","15寸", "16寸"]去按顺序一项一项的去组合,组合完之后将 result = res,

            //以此类推便出现了最终的所有值的组合结果,很巧妙的一个套路,自己去从0开始写还是比较费脑筋的,尤其逻辑处理能力尚不强的时候以及没多少经验的时候

 

方法二:递归调用

这个方法稍微理解起来有点绕

    const generateCombinations = (arr, result = [], current = {}, i = 0)=>{
      // 由于arr.length的长度一般都不会等于,所以最开始直接执行else
      // 第二次函数调用i等于1,而数组长度依旧为3,所以还是执行else
      // 第三次函数调用,此时i等于2,数组长度依旧为3,所以还是执行else
      // 第四次函数调用,此时i等于3,i已经等于数组长度了,故执行if,此时current为,i5 {颜色: '白色', 尺寸: '14寸', 处理器: 'i5'},
      // 当第四次函数调用完之后执行return result,但是函数之前的循环并没有终止掉,上一步的循环停留在调用递归的地方
      // 而此时函数执行到处理器规格的specs循环的第二遍,此时current等于i7 {颜色: '白色', 尺寸: '14寸', 处理器: 'i7'},i还是之前的没有加一的i所以为2
      // 于是再次执行又要递归i再次加1等于3
      // 后面就不解释了,直接看打印值,很巧妙的一种方法,理解起来稍微有点绕不如笛卡尔积写法
          if (i === arr.length) {
            console.log('执行push');
            result.push({...current});
          } else {
            for (const value of arr[i].specs) {
              // 第一次循环(此处第一次循环为颜色规格的specs第一次循环)current[arr[i].name]的arr[i].name值为:'颜色',而value为颜色规格的每一项,
              // 此时循环第一次之后arr不变,result不变,current为 白色 {颜色: '白色'},i+1等于1,然后执行递归
              // 第二次循环,由于执行了递归,第二次循环变成了循环尺寸规格的specs,
              // 此时current为 14寸 {颜色: '白色', 尺寸: '14寸'},i+1等于2,然后再次递归,
              // 第三次循环,由于执行了递归,第三次循环变成了循环处理器规格的specs,
              // 此时current为 i5 {颜色: '白色', 尺寸: '14寸', 处理器: 'i5'},i+1等于3,然后再次递归,
                current[arr[i].name] = value;
                console.log(arr[i].name,'----',value,current,i);
              generateCombinations(arr, result, current, i + 1);
            }
          }
          return result;
        }
      console.log(generateCombinations(data));

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值