前端有多少事情可以做,能做到多好。一直在关注各大公司UED方面的知识,他们也代表了前端的力量,而且也很乐意和大家分享,把应用到项目的知识归类整理,再写成博客搬到网上来,充实这前端的内容,也是为想追寻和学习的人提供了场所,为想接触到一些前沿的知识提供了去处,感谢有这么一群人。大的科技公司基本都有自己的前端部门或团队,在网上也能看到他们的动态,像淘宝、阿里巴巴、腾讯、百度等等。

前段时间在淘宝UED官网上看到一篇SKU组合查询算法探索,当时看过以后只是感觉挺牛的,而且讲的很具体,实现步骤和代码都想说的很详细,几种算法以及算法的复杂度都很有深入的分析,挺佩服这种专研精神的,当时只是隐约的感觉到这个算法在解决电商的商品拆分属性选择中可能会用到,但是具体的实现细节也没进行尝试。

后来公司正好要做一个项目,而且用的就是淘宝商品数据结构,商品详情页是属性选择也和淘宝的很类似,当时就想到了那篇文章,于是有反复看来两三遍,试了一下上面说的第二种算法(已经给出了源码),实现起来也不麻烦,虽然例子中给出的第二种算法得到的结果只有商品数量,但是经过修改也可以得到商品的价格,本打算这样就可以直接用的项目中好了。但是在看到第二种算法的优化后(没有提供源码),就想按照这种方式来实现,也是最初萌发出来的想法一致。

第二种算法会有大量的组合,它是基于原始属性值的结果组合和递归,而不是基于结果集的。其实第二种算法的优化,基于结果集的算法实现起来也不麻烦,原理就是把结果集的SKU中key值进行更小拆分组合,把拆分和组合后的结果信息放到SKUResult里面,这样在初始化一次完成,后面的选择可以根据这个结果集使用。把组合范围减少到key里面,这样能够搜索范围避免递归,而且得到的每个小的组合属性值的结果有用信息很丰富,数量和价格都包括其中。

但是又过了一段时间以后,项目被搁浅了,也不知道以后能用上不能了,写的示例也搁了许久,再不拿出来晾晾估计都该长毛变味了。

示例如下

测试地址: http://jsfiddle.net/tianshaojie/aGggS/

下载地址:http://files.cnblogs.com/purediy/sku-20140802.rar

主要JS代码实现如下

var startTime = new Date().getTime();
//属性集
var keys = [['10'],['20','21','22','23','24'],['30','31','32','33','34','35','36','37','38'],['40']];//后台读取结果集
var data = {"10;24;31;40": {price:366,count:46},"10;24;32;40": {price:406,count:66},"10;24;33;40": {price:416,count:77},"10;24;34;40": {price:456,count:9},"10;24;35;40": {price:371,count:33},"10;24;36;40": {price:411,count:79},"10;24;37;40": {price:421,count:87},"10;24;38;40": {price:461,count:9},"10;24;30;40": {price:356,count:59},"10;23;31;40": {price:366,count:50},"10;23;32;40": {price:406,count:9},"10;23;33;40": {price:416,count:90},"10;23;34;40": {price:456,count:10},"10;23;35;40": {price:371,count:79},"10;23;36;40": {price:411,count:90},"10;23;37;40": {price:421,count:10},"10;23;38;40": {price:461,count:9},"10;23;30;40": {price:356,count:46},"10;22;31;40": {price:356,count:27},"10;22;32;40": {price:396,count:38},"10;22;33;40": {price:406,count:42},"10;22;34;40": {price:446,count:50},"10;22;35;40": {price:361,count:25},"10;22;36;40": {price:401,count:40},"10;22;37;40": {price:411,count:43},"10;22;38;40": {price:451,count:42},"10;21;31;40": {price:366,count:79},"10;21;32;40": {price:406,count:79},"10;21;33;40": {price:416,count:10},"10;21;34;40": {price:456,count:10},"10;21;35;40": {price:371,count:87},"10;21;36;40": {price:411,count:10},"10;21;37;40": {price:421,count:10},"10;21;38;40": {price:461,count:80},"10;21;30;40": {price:356,count:43},"10;20;31;40": {price:356,count:46},"10;20;32;40": {price:396,count:49},"10;20;33;40": {price:406,count:65},"10;20;34;40": {price:446,count:10},"10;20;35;40": {price:361,count:34},"10;20;36;40": {price:401,count:41},"10;20;37;40": {price:411,count:36},"10;20;38;40": {price:451,count:42},"10;20;30;40": {price:346,count: 3}
}
//保存最后的组合结果信息
var SKUResult = {};
//获得对象的key
function getObjKeys(obj) {if (obj !== Object(obj)) throw new TypeError('Invalid object');var keys = [];for (var key in obj)if (Object.prototype.hasOwnProperty.call(obj, key))keys[keys.length] = key;return keys;
}//把组合的key放入结果集SKUResult
function add2SKUResult(combArrItem, sku) {var key = combArrItem.join(";");if(SKUResult[key]) {//SKU信息key属性·SKUResult[key].count += sku.count;SKUResult[key].prices.push(sku.price);} else {SKUResult[key] = {count : sku.count,prices : [sku.price]};}
}//初始化得到结果集
function initSKU() {var i, j, skuKeys = getObjKeys(data);for(i = 0; i < skuKeys.length; i++) {var skuKey = skuKeys[i];//一条SKU信息keyvar sku = data[skuKey];  //一条SKU信息valuevar skuKeyAttrs = skuKey.split(";"); //SKU信息key属性值数组skuKeyAttrs.sort(function(value1, value2) {return parseInt(value1) - parseInt(value2);});//对每个SKU信息key属性值进行拆分组合var combArr = combInArray(skuKeyAttrs);for(j = 0; j < combArr.length; j++) {add2SKUResult(combArr[j], sku);}//结果集接放入SKUResultSKUResult[skuKeyAttrs.join(";")] = {count:sku.count,prices:[sku.price]}}
}/*** 从数组中生成指定长度的组合*/
function arrayCombine(targetArr) {if(!targetArr || !targetArr.length) {return [];}var len = targetArr.length;var resultArrs = [];// 所有组合for(var n = 1; n < len; n++) {var flagArrs = getFlagArrs(len, n);while(flagArrs.length) {var flagArr = flagArrs.shift();var combArr = [];for(var i = 0; i < len; i++) {flagArr[i] && combArr.push(targetArr[i]);}resultArrs.push(combArr);}}return resultArrs;
}/*** 获得从m中取n的所有组合*/
function getFlagArrs(m, n) {if(!n || n < 1) {return [];}var resultArrs = [],flagArr = [],isEnd = false,i, j, leftCnt;for (i = 0; i < m; i++) {flagArr[i] = i < n ? 1 : 0;}resultArrs.push(flagArr.concat());while (!isEnd) {leftCnt = 0;for (i = 0; i < m - 1; i++) {if (flagArr[i] == 1 && flagArr[i+1] == 0) {for(j = 0; j < i; j++) {flagArr[j] = j < leftCnt ? 1 : 0;}flagArr[i] = 0;flagArr[i+1] = 1;var aTmp = flagArr.concat();resultArrs.push(aTmp);if(aTmp.slice(-n).join("").indexOf('0') == -1) {isEnd = true;}break;}flagArr[i] == 1 && leftCnt++;}}return resultArrs;
} //初始化用户选择事件
$(function() {initSKU();var endTime = new Date().getTime();$('#init_time').text('init sku time: ' + (endTime - startTime) + " ms");$('.sku').each(function() {var self = $(this);var attr_id = self.attr('attr_id');if(!SKUResult[attr_id]) {self.attr('disabled', 'disabled');}}).click(function() {var self = $(this);//选中自己,兄弟节点取消选中self.toggleClass('bh-sku-selected').siblings().removeClass('bh-sku-selected');//已经选择的节点var selectedObjs = $('.bh-sku-selected');if(selectedObjs.length) {//获得组合key价格var selectedIds = [];selectedObjs.each(function() {selectedIds.push($(this).attr('attr_id'));});selectedIds.sort(function(value1, value2) {return parseInt(value1) - parseInt(value2);});var len = selectedIds.length;var prices = SKUResult[selectedIds.join(';')].prices;var maxPrice = Math.max.apply(Math, prices);var minPrice = Math.min.apply(Math, prices);$('#price').text(maxPrice > minPrice ? minPrice + "-" + maxPrice : maxPrice);//用已选中的节点验证待测试节点 underTestObjs$(".sku").not(selectedObjs).not(self).each(function() {var siblingsSelectedObj = $(this).siblings('.bh-sku-selected');var testAttrIds = [];//从选中节点中去掉选中的兄弟节点if(siblingsSelectedObj.length) {var siblingsSelectedObjId = siblingsSelectedObj.attr('attr_id');for(var i = 0; i < len; i++) {(selectedIds[i] != siblingsSelectedObjId) && testAttrIds.push(selectedIds[i]);}} else {testAttrIds = selectedIds.concat();}testAttrIds = testAttrIds.concat($(this).attr('attr_id'));testAttrIds.sort(function(value1, value2) {return parseInt(value1) - parseInt(value2);});if(!SKUResult[testAttrIds.join(';')]) {$(this).attr('disabled', 'disabled').removeClass('bh-sku-selected');} else {$(this).removeAttr('disabled');}});} else {//设置默认价格$('#price').text('--');//设置属性状态$('.sku').each(function() {SKUResult[$(this).attr('attr_id')] ? $(this).removeAttr('disabled') : $(this).attr('disabled', 'disabled').removeClass('bh-sku-selected');})}});
});

收获

JavaScript中的对象属性访问是最快的了

[原] 淘宝SKU组合查询算法实现相关推荐

  1. sku组合查询算法探索

    2019独角兽企业重金招聘Python工程师标准>>> sku组合查询算法探索 http://ued.taobao.org/blog/2012/07/sku-search-algor ...

  2. 基于Vue的淘宝SKU组合算法

    现有需求,当点击颜色时进行校验,若蓝色6.0寸无库存时禁选. 先上效果截图: 当前规格组合中 蓝色6寸 和 黑色中6寸 的库存均为0.后台返回数据如下图:实现思路: 例如:当选择蓝色时,进行循环遍历组 ...

  3. 购物车多sku组合查询算法

    基于项目中用到的多sku 选择的问题,提几点参考意见 思路 示例代码 github 思路 针对多sku 选择的问题,当选中某一个规格的时候,目的是需要匹配出所有包含当前此项的所有可能的sku,随后视图 ...

  4. 电商sku组合查询状态细究与实现

    作者 | 朱徽 最近做到一个需求,需要做一个类似于京东或者淘宝等电商的商品详情页,其中有一个功能就是商品SKU的选择查询问题 如上图,网络类型.机身颜色.套餐类型.存储容量这些每一个都是一个 SKU属 ...

  5. 淘宝API接口( item_detail - 淘宝商品详情查询)

    欢迎使用淘宝API接口( item_detail - 淘宝商品详情查询) 点击注册 你好! 这是你使用我们的淘宝API接口获取商品详细接口说明 开通账号联系:Q1140666069 V13879028 ...

  6. 使用淘宝的IP查询API实现IP地址省市展示

    在好多的应用中需要对用户的IP地址进行实际地址显示,这时候就需要对IP进行解析,可以采用TX的IP地址库去查询,但是这个动态库需要补断的更新比较麻烦,现在我们可以直接使用淘宝的IP查询接口来直接调用, ...

  7. 设置淘宝sku方法技巧 淘宝SKU如何设置

    淘宝sku是什么意思?相信商家们对宝贝的sku都很清楚,sku带来的产品的不同颜色.尺寸.但是设置sku并不是一件简单的事情哦,它对店铺的权重和转化都是有一定的联系的.那么sku应该如何正确的去设置呢 ...

  8. 淘宝手机所在地查询接口

    淘宝手机所在地查询接口 https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=(电话号码)

  9. 淘宝/天猫优惠券查询 API 返回值说明

    以下是行业内了解到的一些情况,本帖只展示部分代码,需要更多API调试请移步注册API账号 http://console.open.onebound.cn/console/?i=Turbo 万邦淘宝/天 ...

最新文章

  1. Java中 与,||与|的区别
  2. React 组件js文件中如何引入其他的js 文件数组
  3. Android 获取 AudioRecord 麦克风音量大小并做选择性发送
  4. 魅族升级鸿蒙,魅族要“弯道超车”?率先升级鸿蒙OS,挥别安卓系统
  5. 两个半月!出差终于结束啦
  6. hiveql笔记(一)
  7. pat天梯赛L2-010. 排座位
  8. php serialize取值,PHP 序列化(serialize)格式详解
  9. 机器人编程与python语言的区别_儿童编程和机器人编程有啥区别?
  10. 一线大厂青睐的前端人,90%满足这3个条件
  11. 牛牛牛!干翻Sci-hub!
  12. OpenShift 4 Hands-on Lab (10) 限制集群资源的使用量
  13. 软件外包的话居然会有这样的后果...
  14. Go语言中正则表达式的使用
  15. Kafka Simple Consumer
  16. 旭荣管理软件怎么修改小票内容_水果门店管理系统怎么管理水果门店的
  17. 【转】UMD文件结构(文件解析)
  18. QQ连连看外挂开发过程记录
  19. Dialog dismiss 和 cancel的区别
  20. zh-cn、en-us、zh-tw等表示语言(文化)代码与国家地区对照表

热门文章

  1. Alexnet结构及代码
  2. 【杂谈】我在有三AI从学生到老师
  3. 【每周CV论文】深度学习文本检测与识别入门必读文章
  4. 全球与中国光电通信芯片市场数据专项调研及竞争格局分析报告2022-2028年版
  5. asp.net中的窗体身份验证
  6. 第八回:品味类型---值类型与引用类型(上)-内存有理
  7. C#创建Word文档
  8. JAVA字符串的替换replace、replaceAll、replaceFirst的区别解析。
  9. python2.7 安装pycrypto库报错
  10. Linux cp命令 拷贝文件