速度提高几百倍,记一次数据结构在实际工作中的运用

原创
01/06 11:07
阅读数 3.5W

这段时间写了一堆源码解析,这篇文章想换换口味,跟大家分享一个我工作中遇到的案例。毕竟作为一个打工人,上班除了摸鱼看源码外,砖还是要搬的。本文会分享一个使用恰当的数据结构来进行性能优化,从而大幅提高响应速度的故事,提高有几百倍那么多。

事情是这样的,我现在供职一家外企,我们有一个给外国人用的线下卖货的APP,卖的商品有衣服,鞋子,可乐什么的。某天,产品经理找到我,提了一个需求:需要支持三层的产品选项。听到这个需求,我第一反应是我好像没有见到过三层的产品选项,毕竟我也是一个十来年的资深剁手党,一般的产品选项好像最多两层,比如下面是某电商APP一个典型的鞋子的选项:

这个鞋子就是两层产品选项,一个是颜色,一个是尺码,颜色总共有11种,尺码总共也是11种。为了验证我的直觉,我把我手机上所有的购物APP,啥淘宝,京东,拼多多,苏宁易购全部打开看了一遍。在我看过的商品中,没有发现一个商品有三层选项的,最多也就两层

本文可运行的示例代码已经上传GitHub,大家可以拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/DataStructureAndAlgorithm/OptimizeVariations

为什么没人做三层选项?

一两家不做这个,可能是各家的需求不一样,但是大家都不做,感觉事情不对头。经过仔细分析后,我觉得不做三层选项可能有以下两个原因:

1. 这可能是个伪需求

上面这个鞋子有11种颜色,11种尺码,意味着这些选项后面对应的是11 * 11,总共121个商品。如果再来个第三层选项,假设第三层也有11个选项,那对应的商品总共就是11 * 11 * 11,也就是1331个商品,好多店铺总共可能都没有1331个商品。也就是说,第三层选项可能是个伪需求,用户并没有那么多选项放在第三层,还是以上面的鞋子为例,除了颜色,尺码外,非要再添一个层级,那只能是性别了,也就是男鞋和女鞋。对于男鞋和女鞋来说,版型,尺码这些很不一样,一般都不会放到一个商品下面,更常用的做法是分成两个商品,各自有自己的颜色和尺码。

2. 有性能问题

仅仅是加上第三层选项这个功能并没有什么难的,也就是多展示几个可以点击的按钮而已,点击逻辑跟两层选项并没有太大区别。但是细想下去,我发现了他有潜在的性能问题。以上面这双鞋子为例,我从后端API拿到的数据是这样的:

const merchandise = {
  // variations存放的是所有选项
  variations: [
    {
      name'颜色',
      values: [
        { name'限量版574海军蓝' },
        { name'限量版574白粉' },
        // 下面还有9个
      ]
    },
    {
      name'尺码',
      values: [
        { name'38' },
        { name'39' },
        // 下面还有9个
      ]
    },
  ],
  // products数组存放的是所有商品
  products: [
    {
      id1,
      price208,
      // 与上面variations的对应关系在每个商品的variationMappings里面
      variationMappings: [
        { name'颜色'value'限量版574白粉' },
        { name'尺码'value'38'},
      ]
    },
    // 下面还有一百多个产品
  ]
}

上面这个结构本身还是挺清晰的,merchandise.variations是一个数组,有几层选项,这个数组就有几个对象,每个对象的name就是当前层级的名字,values就是当前层级包含的选项,所以merchandise.variations可以直接拿来显示在UI上,将他们按照层级渲染成按钮就行。

上面图片中,用户选择了第一层的限量版574白粉,第二层的4041等不存在的商品就自动灰掉了。用上面的数据结构可以做到这个功能,当用户选择限量版574白粉的时候,我们就去遍历merchandise.products这个数组,这个数组的一个项就是一个商品,这个商品上的variationMappings会有当前商品的颜色尺码信息。对于我当前的项目来说,如果这个商品可以卖,他就会在merchandise.products这个数组里面,如果不可以卖,这个数组里面压根就不会有这个商品。比如上图的限量版574白粉40码的组合就不会出现在merchandise.products里面,查找的时候找不到这个组合,那就会将它变为灰色,不可以点。

所以对于限量版574白粉40这个鞋子来说,为了知道它需不需要灰掉,我需要整个遍历merchandise.products这个数组。按照前面说的11个颜色,11个尺码来说,最多会有121个商品,也就是最多查找121次。同样的要知道限量版574白粉41这个商品可以不可以卖,又要整个遍历商品数组,11个尺码就需要将商品数组整个遍历11次。对于两层选项来说,11 * 11已经算比较多的了,每个尺码百来次运算可能还不会有严重的性能问题。但是如果再加一层选项,新加这层假如也有11个可选项,这复杂度瞬间就增加了一个指数,从 变成 !现在我们的商品总数是11 * 11 * 11,也就是1331个商品,假如第三层是性别,现在为了知道限量版574白粉40男性这个商品可不可以卖,我需要遍历1331个商品,如果遍历121个商品需要20ms,还比较流畅,那遍历1331个商品就需要220ms,这明显可以感觉到卡顿了,在某些硬件较差的设备上,这种卡顿会更严重,变得不可接受了。而且我们APP使用的技术是React Native,本身性能就比原生差,这样一来,用户可能就怒而卸载了!

我拿着上述对需求的疑问,和对性能的担心找到了产品经理,发生了如下对话:

我:大佬,我发现市面上好像没有APP支持三层选项的,这个需求是不是有问题哦,而且三层选项相较于两层选项来说,复杂度是指数增长,可能会有性能问题,用户用起来会卡的。

产品经理:兄弟,你看的都是国内的APP,但是我们这个是给外国人用的,人家外国人就是习惯这么用,咱要想卖的出去就得满足他们的需求。太卡了肯定不行,性能问题,想办法解决嘛,这就是在UI上再加几个按钮,设计图都跟以前是一样的,给你两天时间够了吧~

我:啊!?额。。。哦。。。

咱也不认识几个外国人,咱也不敢再问,都说了是用户需求,咱必须满足了产品才卖的出去,产品卖出去了咱才有饭吃,想办法解决吧!

解决方案

看来这个需求是必须要做了,这个功能并不复杂,因为三层选项可以沿用两层选项的方案,继续去遍历商品数组,但是这个复杂度增长是指数级的,即从 变成 ,用户用起来会卡。现在,我需要思考一下,有没有其他方案可以提高性能。经过仔细思考,我发现,这种指数级的复杂度增长是来自于我们整个数组的遍历,如果我能够找到一个方法不去遍历这个数组,立即就能找到限量版574白粉40男性对应的商品存不存在就好了。

这个具体的问题转换一下,其实就是:在一个数组中,通过特定的过滤条件,查找符合条件的一个项。嗯,查找,听起来蛮耳熟的,现在我之所以需要去遍历这个数组,是因为这些查找条件跟商品间没有一个直接的对应关系,如果我能建立一个直接的对应关系,不就可以一下就找到了吗?我想到了:查找树假如我重组这些层级关系,将它们组织为一颗树,每个商品都对应树上的一个叶子节点,我可以将三层选项的查找复杂度从 降到

两层查找树

为了说明白这个算法,我先简化这个问题,假设我们现在有两层选项,颜色尺码,每层选项有两个可选项:

  1. 颜色:白色,红色

  2. 尺码:39,40

我们现在对应有4个商品:

  1. 一号商品:productId为1,白色,39码

  2. 二号商品:productId为2,白色,40码

  3. 三号商品:productId为3,红色,39码

  4. 四号商品:productId为4,红色,40码

如果按照最简单的做法,为了查找红色39码鞋子存不存在,我们需要遍历所有的这四个商品,这时候的时间复杂度为 。但是如果我们构建像下面这样一颗树,可以将时间复杂度降到

image-20201117160534500

上面这颗树,我们忽略root节点,在本例中他并没有什么用,仅仅是一个树的入口,这棵树的第一层淡黄色节点是我们第一层选项颜色,第二层淡蓝色节点是我们的第二层选项尺码,只是每个颜色节点都会对应所有的尺码,这样我们最后第二层的叶子节点其实就对应了具体的商品。现在我们要查找红色39码鞋子,只需要看图中红色箭头指向的节点上有没有商品就行了。

那这种数据结构在JS中该怎么表示呢?其实很简单,一个对象就行了,像这样:

const tree = {
  "颜色:白色": {
    "尺码:39": { productId1 },
    "尺码:40": { productId2 }
  },
  "颜色:红色": {
    "尺码:39": { productId3 },
    "尺码:40": { productId4 }
  }
}

有了上面这个数据结构,我们要查找红色39码直接取值tree["颜色:红色"]["尺码:39"]就行了,这个复杂度瞬间就变为 了。

三层查找树

理解了上面的两层查找树,要将它扩展到三层就简单了,直接再加一层就行了。假如我们现在第三层选项是性别,有两个可选项,那我们的查找树就是这样子的:

image-20201118133333379

对应的JS对象:

const tree = {
  "颜色:白色": {
    "尺码:39": { 
     "性别:男": { productId1 },
      "性别:女": { productId2 },
    },
    "尺码:40": { 
     "性别:男": { productId3 },
      "性别:女": { productId4 },
    }
  },
  "颜色:红色": {
    "尺码:39": { 
     "性别:男": { productId5 },
      "性别:女": { productId6 },
    },
    "尺码:40": { 
     "性别:男": { productId7 },
      "性别:女": { productId8 },
    }
  }
}

同样的,假如我们要查找一个白色的,39码的鞋子,直接tree["颜色:白色"]["尺码:39"]["性别:男"]就行了,这个时间复杂度也是

写代码

上面算法都弄明白了,剩下的就是写代码了,我们主要需要写的代码就是用API返回的数据构建一个上面的tree这种结构就行了,一次遍历就可以做到。比如上面这个三层查找树对应的API返回的结构是这样的:

const merchandise = {
  variations: [
    {
      name'颜色',
      values: [
        { name'白色' },
        { name'红色' },
      ]
    },
    {
      name'尺码',
      values: [
        { name'39' },
        { name'40' },
      ]
    },
    {
      name'性别',
      values: [
        { name'男' },
        { name'女' },
      ]
    },
  ],
  products: [
    {
      id1,
      variationMappings: [
        { name'颜色'value'白色' },
        { name'尺码'value'39' },
        { name'性别'value'男' }
      ]
    }
    // 下面还有7个商品,我就不重复了
  ]
}

为了将API返回的数据转换为我们的树形结构数据我们写一个方法:

function buildTree(apiData{
  const tree = {};
  const { variations, products } = apiData;

  // 先用variations将树形结构构建出来,叶子节点默认值为null
  addNode(tree, 0);
  function addNode(root, deep{
    const variationName = variations[deep].name;
    const variationValues = variations[deep].values;

    for (let i = 0; i < variationValues.length; i++) {
      const nodeName = `${variationName}${variationValues[i].name}`;
      if (deep === 2) {
        root[nodeName] = null
      } else {
        root[nodeName] = {};
        addNode(root[nodeName], deep + 1);
      }
    }
  }

  // 然后遍历一次products给树的叶子节点填上值
  for (let i = 0; i < products.length; i++) {
    const product = products[i];
    const { variationMappings } = product;
    const level1Name = `${variationMappings[0].name}${variationMappings[0].value}`;
    const level2Name = `${variationMappings[1].name}${variationMappings[1].value}`;
    const level3Name = `${variationMappings[2].name}${variationMappings[2].value}`;
    tree[level1Name][level2Name][level3Name] = product;
  }

  // 最后返回构建好的树
  return tree;
}

然后用上面的API测试数据运行下看下效果,发现构建出来的树完全符合我们的预期:

image-20201117173553941

这就好了吗?

现在我们有了一颗查找树,当用户选择红色40码后,为了知道对应的可不可以点,我们不需要去遍历所有的商品了,而是可以直接从这个结构上取值。但是这就大功告成了吗?并没有!再仔细看下我们构建出来的数据结构,层级关系是固定的,第一层是颜色,第二层是尺码,第三层是性别,而对应的商品是放在第三层性别上的。也就是说使用这个结构,用户必须严格按照,先选颜色,再选尺码,然后我们看看性别这里哪个该灰掉。如果他不按照这个顺序,比如他先选了性别,然后选尺码40,这时候我们应该计算最后一个层级颜色哪些该灰掉。但是使用上面这个结构我们是算不出来的,因为我们并没有tree["性别:男"]["尺码:40"]这个对象。

这怎么办呢?我们没有性别-尺码-颜色这种顺序的树,那我们就建一颗呗!这当然是个方法,但是用户还可能有其他的操作顺序呀,如果我们要覆盖用户所有可能的操作顺序,总共需要多少树呢?这其实是性别尺码颜色这三个变量的一个全排列,也就是 ,总共6颗树。像我这样的懒人,让我建6棵树,我实在懒得干。如果不建这么多树,需求又覆盖不了,怎么办呢,有没有偷懒的办法呢?如果我能在需求上动点手脚,是不是可以规避这个问题?带着这个思路,我想到了两点:

1. 给一个默认值。

用户打开商品详情页的时候,默认选中第一个可售商品。这样就相当于我们一开始就帮用户按照颜色-尺码-性别这个顺序选中了一个值,给了他一个默认的操作顺序。

2. 不提供取消功能,只能切换选项

如果提供取消功能,他将我们提供的颜色-尺码-性别默认选项取消掉,又可以选成性别-尺码-颜色了。不提供取消功能,只能通过选择其他选项来切换,只能从红色换成白色,而不能取消红色,其他的一样。这样我们就能永远保证颜色-尺码-性别这个顺序,用户操作只是只是每个层级选中的值不一样,层级顺序并不会变化,我们的查找树就一直有效了。而且我发现某些购物网站也不能取消选项,不知道他们是不是也遇到了类似的问题。

对需求做这两点修改并不会对用户体验造成多大影响,跟产品经理商量后,她也同意了。这样我就从需求上干掉了另外5棵树,偷懒成功!

下面是三层选项跑起来的样子:

Nov-18-2020 17-42-28

还有一件事

前面的方案我们解决了查找的性能问题,但是引入了一个新问题,那就是需要创建这颗查找树。创建这颗查找树还是需要对商品列表进行一次遍历,这是不可避免的,为了更顺滑的用户体验,我们应该尽量将这个创建过程隐藏在用户感知不到的地方。我这里是将它整合到了商品详情页的加载状态中,用户点击进入商品详情页,我们要去API取数据,不可避免的会有一个加载状态,会转个圈什么的。我将这个遍历过程也做到了这个转圈中,当API数据返回,并且查找树创建完成后,转圈才会结束。这在理论上会延长转圈的时间,但是本地的遍历再慢也会比网络请求快点,所以用户感知并不明显。当转圈结束后,所有数据都准备就绪了,用户操作都是 的复杂度,做到了真正的丝般顺滑~

为什么不让后端创建这棵树?

上面的方案都是在前端创建这颗树,那有没有可能后端一开始返回的数据就是这样的,我直接拿来用就行,这样我又可以偷懒了~我还真去找过后端,可他给我说:“我也想偷懒!”开个玩笑,真是情况是,这个商品API是另一个团队维护的微服务,他们提供的数据不仅仅给我这一个终端APP使用,也给公司其他产品使用,所以要改返回结构涉及面太大,根本改不动。

封装代码

其实我们这个方案实现本身是比较独立的,其他人要是用的话,他也不关心你里面是棵树还是颗草,只要传入选择条件,能够返回正确的商品就行,所以我们可以将它封装成一个类。

class VariationSearchMap {
    constructor(apiData) {
        this.tree = this.buildTree(apiData);
    }

   // 这就是前面那个构造树的方法
    buildTree(apiData) {
        const tree = {};
        const { variations, products } = apiData;

        // 先用variations将树形结构构建出来,叶子节点默认值为null
        addNode(tree, 0);
        function addNode(root, deep{
            const variationName = variations[deep].name;
            const variationValues = variations[deep].values;

            for (let i = 0; i < variationValues.length; i++) {
                const nodeName = `${variationName}${variationValues[i].name}`;
                if (deep === variations.length - 1) {
                    root[nodeName] = null;
                } else {
                    root[nodeName] = {};
                    addNode(root[nodeName], deep + 1);
                }
            }
        }

        // 然后遍历一次products给树的叶子节点填上值
        for (let i = 0; i < products.length; i++) {
            const product = products[i];
            const { variationMappings } = product;
            const level1Name = `${variationMappings[0].name}${variationMappings[0].value}`;
            const level2Name = `${variationMappings[1].name}${variationMappings[1].value}`;
            const level3Name = `${variationMappings[2].name}${variationMappings[2].value}`;
            tree[level1Name][level2Name][level3Name] = product;
        }

        // 最后返回构建好的树
        return tree;
    }

    // 添加一个方法来搜索商品,参数结构和API数据的variationMappings一样
    findProductByVariationMappings(variationMappings) {
        const level1Name = `${variationMappings[0].name}${variationMappings[0].value}`;
        const level2Name = `${variationMappings[1].name}${variationMappings[1].value}`;
        const level3Name = `${variationMappings[2].name}${variationMappings[2].value}`;

        const product = this.tree[level1Name][level2Name][level3Name];

        return product;
    }
}

然后使用的时候直接new一下就行:

const variationSearchMap = new VariationSearchMap(apiData);    // new一个实例出来

// 然后就可以用这个实例进行搜索了
const searchCriteria = [
    { name'颜色'value'红色' },
    { name'尺码'value'40' },
    { name'性别'value'女' }
];
const matchedProduct = variationSearchMap.findProductByVariationMappings(searchCriteria);
console.log('matchedProduct', matchedProduct);    // { productId: 8 }

总结

本文讲述了一个我工作中实际遇到的需求,分享了我的实现和优化思路,供大家参考。我的实现方案不一定完美,如果大家有更好的方案,欢迎在评论区讨论~

本文可运行的示例代码已经上传GitHub,大家可以拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/DataStructureAndAlgorithm/OptimizeVariations

下面再来回顾下本文的要点:

  1. 本文要实现的需求是一个商品的三层选项。

  2. 当用户选择了两层后,第三层选项应该自动计算出哪些能卖,哪些不能卖。

  3. 鉴于后端API返回选项和商品间没有直接的对应关系,为了找出能卖还是不能卖,我们需要遍历所有商品。

  4. 当总商品数量不多的时候,所有商品遍历可能不会产生明显的性能问题。

  5. 但是当选项增加到三层,商品数量的增加是指数级的,性能问题就会显现出来。

  6. 对于 这种写代码时就能预见的性能问题,我们不用等着报BUG了才处理,而是开发时直接就解决了。

  7. 本例要解决的是一个查找问题,所以我想到了建一颗树,直接将 的复杂度降到了

  8. 但是一颗树并不能覆盖所有的用户操作,要覆盖所有的用户操作需要6棵树。

  9. 出于偷懒的目的,我跟产品经理商量,调整了需求和交互砍掉了5颗树。真实原因是树太多了,会占用更多的内存空间,也不好维护。有时候适当的调整需求和交互也可以达到优化性能的效果,性能优化可以将交互和技术结合起来思考。

  10. 这个树的搜索模块可以单独封装成一个类,外部使用者,不需要知道细节,直接调用接口查找就行。

  11. 前端会点数据结构还是有用的,本文这种场景下还很有必要。

文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。

作者博文GitHub项目地址:https://github.com/dennis-jiang/Front-End-Knowledges

欢迎关注我的公众号进击的大前端第一时间获取高质量原创~

QR1270

展开阅读全文
打赏
14
60 收藏
分享
加载中
能说方向错了吗
01/13 10:27
回复
举报
蒋鹏飞博主
求个正确方向~
01/13 10:54
回复
举报
遍历1331个商品真的需要200+毫秒么?
01/12 10:46
回复
举报
蒋鹏飞博主
嗯,只是随口说的,文中提到过,本文的优化更多是理论上的探讨,实际情况可能不会遇到,文中也提到过可能是个假需求,大部分情况下并没有这么多商品。
01/13 10:54
回复
举报
我想搜 内存槽超过4条 的主板,好像没人提供这个条件
01/11 22:54
回复
举报
发烧平台有很多8条内存的主板,或者服务器
01/12 16:44
回复
举报
蒋鹏飞博主
哈哈,有些专业系统提供类似SQL的查询功能,比如Jira,但是实现成本比较高,大部分针对普通用户的系统实现这个性价比不高,所以没做吧~
01/13 10:53
回复
举报
这个是 业务的问题(没想到 槽数也可能是用户查找的指标),不是 技术的问题。 发烧平台?好像是每个时代的顶级主板了:x79、x99、x299/399。 下单了 dell的二手工作站,e5 2680v3+32Gx4,今天到了,还可以:声音的确安静,可惜截面积不比机架服务器小,无法放进24寸行李箱
01/13 19:55
回复
举报
3*4*2的稀疏矩阵, 数据量两位数.
真不如单层map, n个参数拼接做key. 点击遍历不会有性能问题.
造树有点杀鸡用牛刀了.
01/11 10:10
回复
举报
而且他用树来查找,还对操作的顺序有要求,但实际上界面上所有的条件一开始都是可选的,如果用户一开始先选了尺码呢,或者有更多的条件呢,那他得构造多少课数来解决,或者再想办法搞棵更复杂的树
01/11 10:33
回复
举报
蒋鹏飞博主
单层map可以用,前面有个朋友提到过,我也解释过了:“一层也是可以的,但是一层做不到这个需求:“取出颜色为白色的所有尺码”。使用多层结构,直接tree["白色"]就行了,一层怎么做?至于一层还是多层,看自己的项目需求吧。”
01/13 10:51
回复
举报
我就没想明白为什么要搞棵树去搜索,前端只需要把款码和用户选择的颜色,尺码,性别,传给后端,后端自己去匹配 sku 就不就解决了,根本就不需要搞这么麻烦
01/11 09:42
回复
举报
而且按你的需求描述的情况,假如这个鞋子再加个材质,比如真皮,pua 皮等等,那岂不是一进入页面就要给你上千个 sku 了,还不如让后端给个接口直接去查 sku,如果要考虑网络的问题,每次查 sku 会慢,直接去迭代和过滤一个上千个元素的列表,这个也不存在性能问题啊
01/11 10:20
回复
举报
特定的场景有特定的业务 你这种匹配模式大部分情况下可以坑死后端 数据库的数据除了标识ID什么都不一定是唯一的
01/11 10:36
回复
举报
那即便是前端来匹配 sku 那这样写不就可以了,用树不是反而变的更复杂了? // 假设这是返回的数据 var data = [ {"sku":"sku1", "color":"c1", "size":"s1", "gender":"M", "price":"1.00"}, {"sku":"sku2", "color":"c2", "size":"s1", "gender":"M", "price":"2.00"}, {"sku":"sku3", "color":"c2", "size":"s2", "gender":"M", "price":"3.00"}, {"sku":"sku4", "color":"c1", "size":"s3", "gender":"F", "price":"4.00"} ]; function doSomething(param) { var skus = []; for(var i = 0; i < data.length; i++) { if(param.color != null && data[i].color != param.color) { continue; } if(param.size != null && data[i].size != param.size) { continue; } if(param.gender != null && data[i].gender != param.gender) { continue; } skus.add(data[i]); } return skus; }
01/11 10:50
回复
举报
蒋鹏飞博主
咦,我刚刚的回复怎么不见了,再写一次吧。。。我们第一版代码就是遍历的,遍历实现是最简单的。但是对于需求:选择“白色”后,找出对应的那些尺码可卖,哪些不可卖。如果采用遍历,每次切换颜色,你都需要去遍历所有商品,而有了文中的数据结构,直接可以tree["白色"]拿到,这两个性能差距是指数级的,文中有详细阐述~
01/13 11:00
回复
举报
用树的优点是可以不用遍历整个列表,就能找出需要数据,但是缺点你自己也总结了,就是会限制用户操作的顺序以及不能撤销已选的条件,要支持这种功能,你就需要更多的树,这样一来代价就太大了,搞成负优化了(你们产品也太好忽悠了)。 而且你可以先找后端统计下数据量,看下最多的一款商品有多少个 sku,平均有多少,计算下期望什么的,根据这个结果,再去评估值不值得搞棵数去搜索。
01/13 11:19
回复
举报
蒋鹏飞博主
我们评估了,可以搞!你可能对我文中说的调整需求有误解,这里的调整并不是给产品说,需求必须改,不改做不了! 而是把技术上可行的方案和可能的效果都给他说了,技术上的需求讲清楚,然后看看产品的需求,产品其实自己也是偏向给一个默认值的(给默认值某些场景下使用更方便),技术上有需求只是强化了他的这个想法。所以技术上的需求其实跟产品需求是契合的,这就是优化!
01/13 13:53
回复
举报
非常感谢
01/11 08:32
回复
举报
蒋鹏飞博主
客气了~
01/13 10:47
回复
举报
可以,我一直都是这么干的,但是想到要写个博客的,估计你是第一个
01/07 09:16
回复
举报
蒋鹏飞博主
哈哈,我还真不是第一个,其他平台有朋友提到,几年前就看到过类似想法的文章: https://www.cnblogs.com/dennisj/p/14030280.html#4751219
01/07 12:24
回复
举报
咋没有三层的,电脑配置考虑一下, 内存,CPU, 显示屏,显卡,硬盘 这都5层了; 平台或者商家为了省SKU, 只放了两层而已,让没有的选项自己联系小2改配置和价格了,其实是麻烦用户了。
01/06 17:06
回复
举报
蒋鹏飞博主
嗯,后面我发现其实有三层的,比如手机,有容量,颜色,有些还有4G和5G的选择,但是这种SKU都比较少。你说的电脑这种需求也是存在的,所以文中说是伪需求并不合适。但是无论几层,技术优化思路都可以参考。
01/06 17:34
回复
举报
就这?
01/06 15:32
回复
举报
蒋鹏飞博主
大佬有啥高见?
01/06 17:31
回复
举报
本质问题就是建立一个反向索引。针对这个场景,用一颗几层高的树来做,思维价值高过工程价值。直接一个map,一层一把梭就完事儿了,所有属性字符串连接起来 ==> 到商品id,简单又好维护。几百几千中不会有性能问题,商品以后到三层四层五层,都不需要改代码,改数据结构。
01/07 11:11
回复
举报
蒋鹏飞博主
一层也是可以的,但是一层做不到这个需求:“取出颜色为白色的所有尺码”。使用多层结构,直接tree["白色"]就行了,一层怎么做?至于一层还是多层,看自己的项目需求吧。
01/07 12:27
回复
举报
是,没理解需求。没毛病。
01/07 14:49
回复
举报
更多评论
打赏
29 评论
60 收藏
14
分享
返回顶部
顶部