(8421.BCD码)加权组合应用

来源:互联网 发布:任易行期货软件 编辑:程序博客网 时间:2024/06/05 03:10
1.分析背景:
在实际开发中碰到的一个问题。(会员等级:白金,金,银,铜)
有一个任务列表,需要根据会员不同身份等级来显示自己可见的任务(即金牌只能看到金牌可见的任务,自己等级见对应的你的任务)。
一般该怎么解决呢?
当然是数据库的任务表上建立一个字段,标明一下该任务是哪个等级可见不就结了,so easy。
2.疑问:
那么问题来了,如果我要跨等级显示呢?即让 铜,金可见,银不可见。即要满足这四个的各种组合。。。(排3列组合公式C(n,m)这么算来着??哈哈)
3.方法:
方法一:如上边提到的,建一个新字段varchar类型,并列的用逗号分隔,存储哪些等级可见。比如 "金" 或者 "金,铜"。(不方便select)
方法二:建一个int新字段,使用(8421方法)来加权值区分。

4.分析:
方法一好处是直观,直接知道哪个等级可见,缺点也显而易见,我存4个等级岂不是要写3个逗号分隔,而且这样是不利于select查询的啊。方法二只要建立一个int类型的字段,里边存储一个1~15两位数即可(而且访问量大了int类型的查询不是更快嘛~~)
那么,看看方法二是怎么解决这个问题的。
5.过程
给各个会员等级赋权值如下。
1:铜牌
2:银牌
4:金牌
8:白金
1.在新建任务insert的时候,比如我设置白金,铜牌可见,按上边分配,将权值相加 1+8 = 9,数据库权值字段level就存9。
2. 比如我现在是金牌,如何让我看不到此条数据呢?先查询出我是金牌对应等级为4,把4传入下边函数 toLevelShow(4),返回一个数组,返回值就是涵盖了所有金牌可能参与的组合。返回如下:(4,5,6,7,12,13,14,15) 。(4=4,金),(5=1+4 ,铜+金) (6=2+4,银+金).....很显然铜+白金=9 不再此返回值当中。
3. 在select查询时,select * from table where `level` in ([返回值]),这样就查询出了含有金牌参与的任务了。
6.结论
所以,这个8421权值区分法,本质是统计计算出所有传入值对应的1248组合情况,然后查询的时候where in 这些权里边就行了。
(那么,他是如何找出对应等级的排列的呢这是关键核心。本质加入了2进制数进一的规律方法,详细的可以查看研究下函数。)
此套方法不进局限于会员等级吧,所有符合这种组合分情况显示的情景的都可以使用。
函数如下:    /**     * 输入(1,2,4,8)其中的一个值,返回其1248所有相加的情况组合     * @param 输入,(1,2,4,8)任意一个数     * @return 其所有组合相加的结果     * 比如,输入8,返回array(8,9,10,11,12,13,14,15),     * 因为 8; 8+1=9; 8+2=10; 8+4=12 ; 8+1+2=11 ; 8+1+4=13 ; 8+2+4=14 ; 8+4+2+1=15     * 15是这四个数肯定有的,因为8+4+2+1=15,权值最大     */    function toLevelShow($level_show){        $ret = array();        //把级别转为二进制        $bin = decbin($level_show);        $len = strlen($bin);        for($i=15;$i>=1;$i--){            $tmp = decbin($i);            $tmp = str_pad($tmp, 4,'0',STR_PAD_LEFT);            $tmp1 = substr($tmp,-$len,1);            if($tmp1==1){                $ret[]=$i;            }        }        return $ret;    }

   /**     * 分拆权值,查看是由(1,2,4,8)这四个数字中那几个组合而成     * @param 输入,1-15之间的数,返回1248组合情况。     * @return 1248组成的数组     * 比如,输入15,返回array(1,2,4,8),因为1+2+4+8 = 15     */    function toLevel($level_show){        $ret = array();        //把级别转为二进制         $bin = decbin($level_show);        $len = strlen($bin);        for($i=0;$i<$len;$i++){            $tmp = $len-$i;            if($bin[$i]==1){                $dec = bindec(str_pad($bin[$i], $tmp,'0'));                $ret[]=$dec;            }        }        return $ret;    }



0 0
原创粉丝点击