使用位运算实现网页中的过滤、筛选功能实例

最近屌丝的公司想要为以前的那个网页产品加上一个过滤的功能,废话不多说,直接看筛选的界面是啥样的吧:

可以看出,我们的Message分为Critical、Error等6种类型。现在需要进行过滤,用户可以选择查看其中的一项或多项。

这种需求是很常见的,在大多数情况下,如果可选项是不固定的(比如对于学生信息管理系统,按照班级进行筛选),那么就可能需要借助复杂的SQL语句。例如我们可以写成如下这种形式:

代码如下:

SELECT * FROM [Student] WHERE [ClassId] = 1 OR [ClassId] = 2 OR...

这样就要对SQL语句进行拼接,根据用户选择了哪些内容来动态生成SQL语句。

假如不是数据库操作,而是内存中一片数据的判断,假如用户选择的内容存放在Selected[]数组中,那么对于需要判断的每一项,我们都需要进行一连串的判断操作,需要写一个双重循环。不仅写起来比较复杂,如果项目过多在效率上也令人堪忧。

如果我们需求是像上图那样,Type是固定的并且也不会很多,那么有没有一种比较简单的方式呢?

从标题可以看出,可以使用位运算。在各类高级语言的源代码中大量地运用了这种方式。对于可枚举类型,取值不是顺序的1、2、3、4,而是1、2、4、8按照2的倍数增长,这就是使用二进制位进行判断。

现在我用我刚做的东西来简单叙述一下如何实现吧。当然实现这个很简单,在这里记录更多地是为了增加博文的数量^_^。

在.NET中,一个int类型占4个字节,也就是32位,除去符号位(当然也可以使用无符号整数,这里为了简单期间都使用int),每一位都可以标识一个消息的类型。为此,我们定义枚举类型如下:

代码如下:

public enum CategoryType: int
{
    Unknown = 1,
    Critical = 2,
    Error = 4,
    Warning = 8,
    Information = 16,
    Verbose = 32,
    Other = 1024
}

如果用二进制表示,这些消息分别是0000 0001、0000 0010、0000 0100、0000 1000、00010000、…… 假如用户选择了Unknown、Error和Waring三种类型,把这三个数字相加,就是1+4+8=13,二进制表示就是0000 1101。为1的位正好对应了用户选择的类型,为0的位正好对用用户没选的类型。

在客户端,使用Javascript就可以使用下面这种简单的方式计算用户选择的值:

代码如下:

var category = 0;

if (filterVM.ckType2Checked()) category |= 2;
if (filterVM.ckType4Checked()) category |= 4;
if (filterVM.ckType8Checked()) category |= 8;
if (filterVM.ckType16Checked()) category |= 16;
if (filterVM.ckType32Checked()) category |= 32;
if (filterVM.ckType1024Checked()) category |= 1024;

当然,由于这种特殊的设计,使用加法运算的效果是完全相同的。

这样把用户选择的内容传给服务器就是一个简单的整数,比如上面的13表示用户选择的三种类型。而且在数学上可以证明,对于每一个整数,对应的枚举类型的组合是唯一的(要证明看似很难,但如果使用二进制进行思考便会显而易见)。

在服务器端对每种消息进行判断时,只需要使用与运算,便能知道消息是否在用户选择的范围内(只要结果不等于0,说明某个枚举类型对应的那一位在相加的结果中。如果使用符号位,那么可能会出现负数)。

举两个简单的例子吧,假如客户端传过来的是13(0000 1101),某一种消息是Waring=8(0000 1000),相与的结果为8(0000 1000)与消息的类型相同(只需判断是否不等于0即可)。对于消息为16(0001 0000)的情况,相与的结果肯定是0。代码如下:

代码如下:

for (int i = 0; i < list.Count; i++)
{
    if (((int)list[i].Category & categoryFilter) > 0 && ((int)list[i].Direction & directionFilter) > 0)
        yield return list[i];
}

对于要选出所有的类型的情况,只需要把上述categoryFilter设置为全部为1的数字即可(0x7fffffff,如果使用符号位就是0xffffffff)。

在客户段根据这个相加后的结果进行控件绑定的使用,要判断某个复选框是否应该选中时,按照相同的逻辑相与即可:

代码如下:

this.ckType2Checked((category & 2) > 0);
this.ckType4Checked((category & 4) > 0);
this.ckType8Checked((category & 8) > 0);
this.ckType16Checked((category & 16) > 0);
this.ckType32Checked((category & 32) > 0);
this.ckType1024Checked((category & 1024) > 0);

需要注意的是,这个方法不是万能的。如果可选项是不固定的,使用位运算有可能反而会很麻烦,因为我们要编写程序存储每一种选项对应的数字。

如果可选项是固定的但是数量很多(比如几千种),那么我们可以用一串整数进行表示,也会很方便(当然显示也不会有这样变态的筛选功能,即使有用户也不大可能在几千种里面去选,如果出现这种情况,只能说设计有问题)。

这种做法有一个比较大的弊端,就是改动筛选内容时服务器和客户端都会改。不过还好改动不会太大,只需要改变服务器的enum和客户端的控件即可……

当然这种思想也是今后设计程序时的一种很好参考。

(0)

相关推荐

  • C#运算符之与,或,异或及移位运算小结

    1.剖析异或运算(^) 二元 ^ 运算符是为整型和 bool 类型预定义的.对于整型,^ 将计算操作数的按位"异或".对于 bool 操作数,^ 将计算操作数的逻辑"异或":也就是说,当且仅当只有一个操作数为 true 时,结果才为 true. 数值运算举例 按位异或的3个特点:(1) 0^0=0,0^1=1  0异或任何数=任何数(2) 1^0=1,1^1=0  1异或任何数-任何数取反(3) 1^1=0,0^0=0  任何数异或自己=把自己置0 例如:10100

  • C# 位运算符整理

    C#支持的位逻辑运算符如表2.9所示. 运算符号 意义 运算对象类型 运算结果类型 对象数 实例 ~ 位逻辑非运算 整型,字符型 整型 1 ~a & 位逻辑与运算 2 a & b | 位逻辑或运算 2 a | b ^ 位逻辑异或运算 2 a ^ b <<  位左移运算 2 a<<4 >>  位右移运算 2 a>>2 1.位逻辑非运算 位逻辑非运算是单目的,只有一个运算对象.位逻辑非运算按位对运算对象的值进行非运算,即:如果某一位等于0,就将其

  • C#枚举中的位运算权限分配浅谈

    常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第一步, 先建立一个枚举表示所有的权限管理操作: 复制代码 代码如下: [Flags] public enum Permissions { Insert = 1, Delete = 2, Update = 4, Query = 8 } [Flags]表示该枚举可以支持C#位运算, 而枚举的每一项值, 我们用2的

  • 使用位运算实现网页中的过滤、筛选功能实例

    最近屌丝的公司想要为以前的那个网页产品加上一个过滤的功能,废话不多说,直接看筛选的界面是啥样的吧: 可以看出,我们的Message分为Critical.Error等6种类型.现在需要进行过滤,用户可以选择查看其中的一项或多项. 这种需求是很常见的,在大多数情况下,如果可选项是不固定的(比如对于学生信息管理系统,按照班级进行筛选),那么就可能需要借助复杂的SQL语句.例如我们可以写成如下这种形式: 复制代码 代码如下: SELECT * FROM [Student] WHERE [ClassId]

  • js位运算在实际中使用的实例教程

    目录 什么是位运算? 业务场景: 解决办法 办法一: 办法二: 附:位运算的综合应用 总结 什么是位运算? 从现代计算机中所有的数据二进制的形式存储在设备中.即 0.1 两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 按位运算符有6个 &: 按位与\|: 按位或\^: 按位异或\~: 按位取反\>> : 右移\<<: 左移 业务场景: 我们大部分的业务开发场景下 只用if else 或 switch 条件处理就可以,但是

  • python获取网页中所有图片并筛选指定分辨率的方法

    压测时,图片太少,想着下载网页中的图片,然后过滤指定分辨率,但网页中指定分辨率的图片太少了(见下) 后使用格式工厂转换图片 import urllib.request # 导入urllib模块 import re # 导入re模块 import os from PIL import Image htmlurl = 'http://www.win4000.com/wallpaper_detail_134824_3.html' downloadpath = 'C:\\Users\\yaowanjun

  • js网页中的(运行代码)功能实现思路

    复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset='utf8' /> <title>网页中的运行代码功能</title> <script type="text/javascript"> function runCode(oCode) { var win = window.open('', "_blank", ''); win

  • 微信小程序中的列表切换功能实例代码详解

    感觉这列表切换有点类似于轮播图,而且感觉这代码直接可以拿来用,稍微改一改样式什么的就OK了,列表切换也是用到的地方也很多 wxml中的代码如下: <!-- 标签页面标题 --> <view class="tab"> <view class="tab-item {{tab==0?'active':''}}" bindtap="changeItem" data-item="0">音乐推荐<

  • JQuery中基础过滤选择器用法实例分析

    本文实例讲述了JQuery中基础过滤选择器用法.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <he

  • JQuery中属性过滤选择器用法实例分析

    本文实例讲述了JQuery中属性过滤选择器用法.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <he

  • Android开发中应用程序分享功能实例

    本文实例讲述了Android开发中应用程序分享功能.分享给大家供大家参考,具体如下: Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); //设置类型 shareIntent.setType("text/plain"); //设置分享的主题 shareIntent.putExtra("android.intent.extra.SUBJECT", "分享&

  • 用JQuery在网页中实现分隔条功能的代码

    Javascript代码如下,将该代码保存成JS文件后在HTML中引用. 复制代码 代码如下: jQuery.noConflict(); jQuery.fn.extend({ jsplit: function (j) { return this.each(function () { j = j || {}; j.Btn = j.Btn || {}; j.Btn.oBg = j.Btn.oBg || {}; j.Btn.cBg = j.Btn.cBg || {}; var jun = { MaxW

  • node.js正则表达式获取网页中所有链接的代码实例

    实现代码 复制代码 代码如下: var http = require('http'); //定义函数var getAHref = function(htmlstr){    var reg = /<a.+?href=('|")?([^'"]+)('|")?(?:\s+|>)/gim;    var arr = [];    while(tem=reg.exec(htmlstr)){        arr.push(tem[2]);    }    return a

随机推荐