标签 数据结构 下的文章

1.遍历数组法

最简单的去重方法, 实现思路:新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;注意点:判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE8以下不支持,需多写一些兼容低版本浏览器代码,源码如下:

// 最简单数组去重法
function unique1(array){
  var n = []; //一个新的临时数组
  //遍历当前数组
  for(var i = 0; i < array.length; i++){
    //如果当前数组的第i已经保存进了临时数组,那么跳过,
    //否则把当前项push到临时数组里面
    if (n.indexOf(array[i]) == -1) n.push(array[i]);
  }
  return n;
}
// 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
if (!Array.prototype.indexOf){
  // 新增indexOf方法
  Array.prototype.indexOf = function(item){
    var result = -1, a_item = null;
    if (this.length == 0){
      return result;
    }
    for(var i = 0, len = this.length; i < len; i++){
      a_item = this[i];
      if (a_item === item){
        result = i;
        break;
      }  
    }
    return result;
  }
}

2.对象键值对法

该方法执行的速度比其他任何方法都快, 就是占用的内存大一些;实现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。注意点: 判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为一样;例如: a[1]、a["1"] 。解决上述问题还是得调用“indexOf”。

// 速度最快, 占空间最多(空间换时间)
function unique2(array){
  var n = {}, r = [], len = array.length, val, type;
    for (var i = 0; i < array.length; i++) {
        val = array[i];
        type = typeof val;
        if (!n[val]) {
            n[val] = [type];
            r.push(val);
        } else if (n[val].indexOf(type) < 0) {
            n[val].push(type);
            r.push(val);
        }
    }
    return r;
}

3.数组下标判断法

还是得调用“indexOf”性能跟方法1差不多,实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。

function unique3(array){
  var n = [array[0]]; //结果数组
  //从第二项开始遍历
  for(var i = 1; i < array.length; i++) {
    //如果当前数组的第i项在当前数组中第一次出现的位置不是i,
    //那么表示第i项是重复的,忽略掉。否则存入结果数组
    if (array.indexOf(array[i]) == i) n.push(array[i]);
  }
  return n;
}

4.排序后相邻去除法

虽然原生数组的”sort”方法排序结果不怎么靠谱,但在不注重顺序的去重里该缺点毫无影响。实现思路:给传入数组排序,排序后相同值相邻,然后遍历时新数组只加入不与前一值重复的值。

// 将相同的值相邻,然后遍历去除重复值
function unique4(array){
  array.sort(); 
  var re=[array[0]];
  for(var i = 1; i < array.length; i++){
    if( array[i] !== re[re.length-1])
    {
      re.push(array[i]);
    }
  }
  return re;
}

5.优化遍历数组法

源自外国博文,该方法的实现代码相当酷炫;实现思路:获取没重复的最右一值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断)

// 思路:获取没重复的最右一值放入新数组
function unique5(array){
  var r = [];
  for(var i = 0, l = array.length; i < l; i++) {
    for(var j = i + 1; j < l; j++)
      if (array[i] === array[j]) j = ++i;
    r.push(array[i]);
  }
  return r;
}

商品类目用于确定商户添加的某种商品是什么类型的,具有哪些特定的销售属性、描述属性或者关键属性,系统在获取一个商品的完整数据前,需要先读取其所属的类型数据,根据类型数据再从数据库中获取其有哪些数据属性。

数据结构

-- Table: catalog_category

-- DROP TABLE catalog_category;

CREATE TABLE catalog_category
(
  id serial NOT NULL, -- ID
  uuid uuid NOT NULL, -- 全局唯一标识
  parent_id integer NOT NULL DEFAULT 0, -- 父级ID
  location character varying(255) NOT NULL DEFAULT '0'::character varying, -- 位置,若为顶级类型,则为 0,否则路径为通过 '/' 连接上级类型的路径与上级的ID而成的字符串,比如ID为 1 的类型的路径为 0,它有一个子分类ID为2,那么子分类2的路径就为 0/1,若该子分类还有一个ID为3的子分类,那么3的位置即为:0/1/2
  name character varying(32) NOT NULL, -- 类型名称
  description character varying(255) DEFAULT ''::character varying, -- 介绍说明
  icon character varying(255) DEFAULT ''::character varying, -- 图标,直接填写图标名称即可
  cover character varying(255) DEFAULT ''::character varying, -- 类型封面图片,图片的URI地址,
  is_parent boolean NOT NULL DEFAULT false, -- 是否为父级分类,若分类有下级分类,则该值为 true,否则为 false,默认为 false。
  is_editable boolean NOT NULL DEFAULT true, -- 是否可编辑
  is_usable boolean NOT NULL DEFAULT true, -- 是否可用
  create_time timestamp with time zone, -- 创建时间
  update_time timestamp with time zone, -- 最后更新时间
  CONSTRAINT catalog_category_pkey PRIMARY KEY (id),
  CONSTRAINT catalog_category_parent_id_fkey FOREIGN KEY (parent_id)
      REFERENCES catalog_category (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT catalog_category_name_key UNIQUE (name)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE catalog_category
  OWNER TO postgres;
COMMENT ON TABLE catalog_category
  IS '商品类型';
COMMENT ON COLUMN catalog_category.id IS 'ID';
COMMENT ON COLUMN catalog_category.uuid IS '全局唯一标识';
COMMENT ON COLUMN catalog_category.parent_id IS '父级ID';
COMMENT ON COLUMN catalog_category.location IS '位置,若为顶级类型,则为 0,否则路径为通过 ''/'' 连接上级类型的路径与上级的ID而成的字符串,比如ID为 1 的类型的路径为 0,它有一个子分类ID为2,那么子分类2的路径就为 0/1,若该子分类还有一个ID为3的子分类,那么3的位置即为:0/1/2';
COMMENT ON COLUMN catalog_category.name IS '类型名称';
COMMENT ON COLUMN catalog_category.description IS '介绍说明';
COMMENT ON COLUMN catalog_category.icon IS '图标,直接填写图标名称即可';
COMMENT ON COLUMN catalog_category.cover IS '类型封面图片,图片的URI地址,';
COMMENT ON COLUMN catalog_category.is_parent IS '是否为父级分类,若分类有下级分类,则该值为 true,否则为 false,默认为 false。';
COMMENT ON COLUMN catalog_category.is_editable IS '是否可编辑';
COMMENT ON COLUMN catalog_category.is_usable IS '是否可用';
COMMENT ON COLUMN catalog_category.create_time IS '创建时间';
COMMENT ON COLUMN catalog_category.update_time IS '最后更新时间';

字段说明

  • uuid : 全局唯一标识,在系统中暂时没有任何用处,只为备用
  • parent_id : 对应系统类型 CatalogCategory 中的 parentId,关键至 catalog_category 表中的 id 字段,用于指定类型的父类型;
  • location : 记录当前类目在类目树中的位置,它是以 / 符号连接的所有父级分类的ID串,若为顶级类型,则为 0,否则路径为通过 ''/'' 连接上级类型的路径与上级的ID而成的字符串,比如ID为 1 的类型的路径为 0,它有一个子分类ID为2,那么子分类2的路径就为 0/1,若该子分类还有一个ID为3的子分类,那么3的位置即为:0/1/2;
  • name :类目的名称
  • description :类目的介绍
  • icon:用于指定类目的图标
  • cover:类目的封面图片地址
  • is_parent:是否为父级类目,若有一个或者多个类目将 parent_id 设置为类目的ID,则这个类目 parent_id 所指定的类目的 is_parent 属性即为 true,否则为 false
  • is_usable:这是系统级的属性,用于确定某一个类目是否可用,若某一个类目的 is_usable 属性为 false,则该类目下面的所有子类目均不可用,因系统的开发过程中,需要考虑到此项。
  • create_time:类目的创建时间
  • update_time:类目信息最后更新时间

最近一直在忙着自己第一个完整的产品,叫 Oak Commerce,橡果电子商务系统,该系统是一个基于平板电脑的提供给线下时尚产业零售和批发商使用的进销存、财务以及客户关系管理系统,系统里面还融合了现在流行的微信营销系统以及在线电子商城系统,该系统中商品类型包括了鞋、帽、衣、裤、围巾等,对于商品数据结构的设计,在我看来,放在了整个系统中的重中之重的地位,为了能帮助自己完全的理清思路,所以,也见解了很多优秀的开源电子商务系统,在自己的博客里,就慢慢地记录这整个过程,这一系列的文章会一直更新到我完成这个数据结构的设计,本文是该系列日志的第一篇,介绍我所需要满足的真实的业务需求。

定义

引用淘宝商品类目数据结构设计中的对属性的归类,商品的属性分为以下三种:

  1. 关键属性:能够确认唯一产品的属性,可以是一个,或者多个关键属性的组合,比如:相机的"品牌""型号"能确定唯一的产品,服装的"品牌""货号"能确定唯一的产品
  2. 销售属性:组成SKU的特殊属性,它会影响买家的购买和卖家的库存管理,如服装的"颜色"、"套餐"和"尺码",注意这里的SKU,淘宝销售属性组合成SKU
  3. 非关键属性:就是商品属性了,一些对商品进行描述的属性

商品的类型

时尚产业中,最常见的商品类型包括下面这几种:

  1. 衣服
  2. 裤子
  3. 鞋子
  4. 帽子
  5. 袜子
  6. 内衣
  7. 内裤
  8. 手套
  9. 帽子
  10. 其它

以上这些商品类型的关键属性均包括以下两个:

  1. 品牌
  2. 货号

库存管理

进销丰系统中的首要任务就是库存管理,而库存受销售属性的影响,根所系统中所有可能出现的商品类型,系统的销售属性可能有下面两个:

  1. 颜色
  2. 尺码

由于品牌的不同,所遵循的尺码标准也不同,所以,系统除了可以根据颜色可尺码对商品进行库存管理外,还需要满足一个条件,那就是尺码可以根据所执行的标准不同而归组,常见的尺码组有下面这些:

  • 中国 160-165/84-86、165-170/88-90、167-172/92-96、168-173/98-102、170-176/106-110
  • 国际 XS、S、M、L、XL
  • 美国 2、4-6、8-10、12-14
  • 欧洲 34、34-36、38-40、42、44

商户在建立任何一种商品的档案时,都可以为该商品自由的指定一种尺码组,而且还可以设定该商品的尺码属性(即有哪些尺码,现实业务中,不可能任何衣服的尺码都从XS 到 XL,有可能XS厂家就不生产),尺码组只要确定,则该商品就不能再选择其它的尺码组了。

同样的颜色具有两种添加方式,一种是单色商品可以直接从系统中选择一种颜色,另一种是多色商品,商户可以选择花色,但是由于一种商品可能出现多种花色,而不同的花色同时有可能也需要进行库存管理,所以,颜色还可以让用户进行自定义,自己起名或者拍照,将一种花色的商品拍照设置成为商品的颜色。

不管是尺码还是颜色,在档案建立之后,均可以添加,但是对于尺码而言,只允许在商品档案现在的尺码组中添加,不允许添加其它尺码组中的尺码。

对商品的描述属性

这些属性不属于关键属性,而是属于描述商品特征的属性,不同的商品类型之间可能有公共的描述属性,也可能有属于某一个类型的特殊描述属性,为了系统的合理性,我们放弃更多的自由度,即商户在选择了商品类型之后,描述属性必需按照系统所制定的标准描述属性添加(可以留空,但不允许添加自定义的描述属性)