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

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

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

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

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

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

復制代碼 代碼如下:

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

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

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

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

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

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

在.NET中,一個int類型占4個字節(jié),也就是32位,除去符號位(當然也可以使用無符號整數(shù),這里為了簡單期間都使用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三種類型,把這三個數(shù)字相加,就是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;

當然,由于這種特殊的設計,使用加法運算的效果是完全相同的。

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

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

舉兩個簡單的例子吧,假如客戶端傳過來的是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的數(shù)字即可(0x7fffffff,如果使用符號位就是0xffffffff)。

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

復制代碼 代碼如下:

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

需要注意的是,這個方法不是萬能的。如果可選項是不固定的,使用位運算有可能反而會很麻煩,因為我們要編寫程序存儲每一種選項對應的數(shù)字。

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

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

當然這種思想也是今后設計程序時的一種很好參考。

相關文章

最新評論

彰武县| 宁武县| 巴林右旗| 孟津县| 福泉市| 阜南县| 柏乡县| 汝阳县| 赫章县| 哈尔滨市| 崇文区| 广州市| 基隆市| 唐河县| 通江县| 西城区| 瓦房店市| 清镇市| 新营市| 收藏| 湘阴县| 乐业县| 仁布县| 金堂县| 太白县| 高陵县| 新野县| 临桂县| 威海市| 辽中县| 清徐县| 剑川县| 黎平县| 抚顺市| 洛南县| 德保县| 新巴尔虎右旗| 美姑县| 卢湾区| 彝良县| 兴化市|