最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用位運(yùn)算實(shí)現(xiàn)網(wǎng)頁中的過濾、篩選功能實(shí)例

 更新時間:2014年07月16日 10:06:41   投稿:junjie  
這篇文章主要介紹了使用位運(yùn)算實(shí)現(xiàn)網(wǎng)頁中的過濾、篩選功能實(shí)例,一個比常規(guī)拼接SQL字符串更有新意的一個解決思路,需要的朋友可以參考下

最近屌絲的公司想要為以前的那個網(wǎng)頁產(chǎn)品加上一個過濾的功能,廢話不多說,直接看篩選的界面是啥樣的吧:

可以看出,我們的Message分為Critical、Error等6種類型?,F(xiàn)在需要進(jìn)行過濾,用戶可以選擇查看其中的一項(xiàng)或多項(xiàng)。

這種需求是很常見的,在大多數(shù)情況下,如果可選項(xiàng)是不固定的(比如對于學(xué)生信息管理系統(tǒng),按照班級進(jìn)行篩選),那么就可能需要借助復(fù)雜的SQL語句。例如我們可以寫成如下這種形式:

復(fù)制代碼 代碼如下:

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

這樣就要對SQL語句進(jìn)行拼接,根據(jù)用戶選擇了哪些內(nèi)容來動態(tài)生成SQL語句。

假如不是數(shù)據(jù)庫操作,而是內(nèi)存中一片數(shù)據(jù)的判斷,假如用戶選擇的內(nèi)容存放在Selected[]數(shù)組中,那么對于需要判斷的每一項(xiàng),我們都需要進(jìn)行一連串的判斷操作,需要寫一個雙重循環(huán)。不僅寫起來比較復(fù)雜,如果項(xiàng)目過多在效率上也令人堪憂。

如果我們需求是像上圖那樣,Type是固定的并且也不會很多,那么有沒有一種比較簡單的方式呢?

從標(biāo)題可以看出,可以使用位運(yùn)算。在各類高級語言的源代碼中大量地運(yùn)用了這種方式。對于可枚舉類型,取值不是順序的1、2、3、4,而是1、2、4、8按照2的倍數(shù)增長,這就是使用二進(jìn)制位進(jìn)行判斷。

現(xiàn)在我用我剛做的東西來簡單敘述一下如何實(shí)現(xiàn)吧。當(dāng)然實(shí)現(xiàn)這個很簡單,在這里記錄更多地是為了增加博文的數(shù)量^_^。

在.NET中,一個int類型占4個字節(jié),也就是32位,除去符號位(當(dāng)然也可以使用無符號整數(shù),這里為了簡單期間都使用int),每一位都可以標(biāo)識一個消息的類型。為此,我們定義枚舉類型如下:

復(fù)制代碼 代碼如下:

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

如果用二進(jìn)制表示,這些消息分別是0000 0001、0000 0010、0000 0100、0000 1000、00010000、…… 假如用戶選擇了Unknown、Error和Waring三種類型,把這三個數(shù)字相加,就是1+4+8=13,二進(jìn)制表示就是0000 1101。為1的位正好對應(yīng)了用戶選擇的類型,為0的位正好對用用戶沒選的類型。

在客戶端,使用Javascript就可以使用下面這種簡單的方式計(jì)算用戶選擇的值:

復(fù)制代碼 代碼如下:

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;

當(dāng)然,由于這種特殊的設(shè)計(jì),使用加法運(yùn)算的效果是完全相同的。

這樣把用戶選擇的內(nèi)容傳給服務(wù)器就是一個簡單的整數(shù),比如上面的13表示用戶選擇的三種類型。而且在數(shù)學(xué)上可以證明,對于每一個整數(shù),對應(yīng)的枚舉類型的組合是唯一的(要證明看似很難,但如果使用二進(jìn)制進(jìn)行思考便會顯而易見)。

在服務(wù)器端對每種消息進(jìn)行判斷時,只需要使用與運(yùn)算,便能知道消息是否在用戶選擇的范圍內(nèi)(只要結(jié)果不等于0,說明某個枚舉類型對應(yīng)的那一位在相加的結(jié)果中。如果使用符號位,那么可能會出現(xiàn)負(fù)數(shù))。

舉兩個簡單的例子吧,假如客戶端傳過來的是13(0000 1101),某一種消息是Waring=8(0000 1000),相與的結(jié)果為8(0000 1000)與消息的類型相同(只需判斷是否不等于0即可)。對于消息為16(0001 0000)的情況,相與的結(jié)果肯定是0。代碼如下:

復(fù)制代碼 代碼如下:

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設(shè)置為全部為1的數(shù)字即可(0x7fffffff,如果使用符號位就是0xffffffff)。

在客戶段根據(jù)這個相加后的結(jié)果進(jìn)行控件綁定的使用,要判斷某個復(fù)選框是否應(yīng)該選中時,按照相同的邏輯相與即可:

復(fù)制代碼 代碼如下:

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);

需要注意的是,這個方法不是萬能的。如果可選項(xiàng)是不固定的,使用位運(yùn)算有可能反而會很麻煩,因?yàn)槲覀円帉懗绦虼鎯γ恳环N選項(xiàng)對應(yīng)的數(shù)字。

如果可選項(xiàng)是固定的但是數(shù)量很多(比如幾千種),那么我們可以用一串整數(shù)進(jìn)行表示,也會很方便(當(dāng)然顯示也不會有這樣變態(tài)的篩選功能,即使有用戶也不大可能在幾千種里面去選,如果出現(xiàn)這種情況,只能說設(shè)計(jì)有問題)。

這種做法有一個比較大的弊端,就是改動篩選內(nèi)容時服務(wù)器和客戶端都會改。不過還好改動不會太大,只需要改變服務(wù)器的enum和客戶端的控件即可……

當(dāng)然這種思想也是今后設(shè)計(jì)程序時的一種很好參考。

相關(guān)文章

最新評論

林州市| 乌拉特中旗| 陆河县| 修武县| 吴川市| 潞西市| 军事| 南和县| 大名县| 湘西| 古蔺县| 屯昌县| 阳谷县| 莱州市| 秦皇岛市| 阳谷县| 綦江县| 卫辉市| 东乡| 宣恩县| 股票| 句容市| 行唐县| 宜城市| 桂东县| 梓潼县| 呈贡县| 饶平县| 称多县| 张家口市| 都昌县| 成武县| 邳州市| 方山县| 健康| 涟水县| 吉林市| 霍城县| 大埔县| 任丘市| 桂林市|