成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

對JavaScript對象數(shù)組按指定屬性和排序方向進(jìn)行排序

z2xy / 1231人閱讀

摘要:對數(shù)據(jù)進(jìn)行排序是必不可少的功能。對簡單的名值對象按照指定屬性和排序方向進(jìn)行排序根據(jù)排序?qū)傩约芭判蚍较?,對兩個項依次進(jìn)行比較,并返回代表排序位置的值。按照指定屬性及升降方向進(jìn)行排序。

標(biāo)簽:JavaScript 對象數(shù)組 排序

引言

在以數(shù)據(jù)為中心的信息系統(tǒng)中,以表格形式展示數(shù)據(jù)是在常見不過的方式了。對數(shù)據(jù)進(jìn)行排序是必不可少的功能。排序可以分為按單個字段排序和按多個字段不同排序方向排序。單字段排序局限性較大,不能滿足用戶對數(shù)據(jù)的關(guān)注點變化的需求,而多字段排序就可以較好的彌補這個缺陷。

多字段排序,實現(xiàn)的方式從大的層面上可以分為后端實現(xiàn)和前端實現(xiàn)。

后端排序

后端實現(xiàn)排序可以在數(shù)據(jù)庫層面實現(xiàn)或者在應(yīng)用程序?qū)用鎸崿F(xiàn)。

數(shù)據(jù)庫層面實現(xiàn)多字段排序非常簡單,使用SQL的排序指令“Order By”即可——Order By field1 asc, field2 desc, field3 asc -- ...

應(yīng)用程序?qū)用媸侵竁eb應(yīng)用層(這里不討論C/S架構(gòu)),比如PHP、Java Web、ASP.NET等。應(yīng)用程序?qū)用鎸崿F(xiàn)就是使用PHP、Java、.NET(C#/VB)這些后端服務(wù)語言來實現(xiàn)對數(shù)據(jù)的排序。以ASP.NET C# 為例,因為C#中的LINQ內(nèi)置了對集合類型的諸多操作,并且支持多屬性排序,所以使用LINQ能夠很方便的實現(xiàn)此目的——from f in foos orderby f.Name descending, f.Num ascending select f(可以發(fā)現(xiàn)LINQ的排序語法幾乎與SQL的一模一樣)。如果其它語言沒有內(nèi)置類似的支持,則按照排序算法來實現(xiàn),這是通用的,與編程語言無關(guān)。

前端排序

在JavaScript中,數(shù)組有一個排序方法“sort”,當(dāng)數(shù)組是一個簡單數(shù)組(數(shù)組元素是簡單類型——字符串、數(shù)值和布爾)時,使用該方法可以很方便的到達(dá)排序目的。但是當(dāng)數(shù)組元素是非簡單類型,比如名/值對的Object,并且想要按照指定的某幾個屬性按不同的排序方向進(jìn)行排序時,簡單的調(diào)用“sort”方法就不能實現(xiàn)此目的了。

不過好在“sort”方法預(yù)留了自定義排序的接口,可以實現(xiàn)想要的排序方式。

來看看數(shù)組的“sort”方法是怎樣的。

sort函數(shù)原型
// 對數(shù)組的元素做原地的排序,并返回這個數(shù)組。
// 默認(rèn)按照字符串的Unicode碼位點(code point)排序。
Array.prototype.sort([compareFunction]:number); // number:-1 | 0 | 1。

// 典型的比較函數(shù)(升序排序)。
function compareFunction(item1, item2) {
    if(item1 > item2) {
        return 1; // 如果是降序排序,返回-1。
    }else if(item1 === item2) {
        return 0;
    }else {
        return -1; // 如果是降序排序,返回1。
    }
}

說明:如果沒有指明compareFunction,那么元素會被轉(zhuǎn)換為字符串的諸個字符并按照Unicode位點順序排序。例如,"Cherry"會被排列到"banana"之前。當(dāng)對數(shù)字進(jìn)行排序的時候, 9 會出現(xiàn)在 80 之前,因為他們會先被轉(zhuǎn)換為字符串,而 "80" 比 "9" 要靠前。

如果 compareFunction(a, b) 小于 0 ,那么 a 會被排列到 b 之前;

如果 compareFunction(a, b) 等于 0 ,a 和 b
的相對位置不變。備注:ECMAScript標(biāo)準(zhǔn)并不保證這一行為,而且也不是所有瀏覽器都會遵守(例如 Mozilla 在 2003

年之前的版本);

如果 compareFunction(a, b) 大于 0 , b 會被排列到 a 之前。

compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結(jié)果,否則排序的結(jié)果將是不確定的。

注:以上規(guī)則得出的排序結(jié)果是升序的,如果想要得到降序的結(jié)果,則在比較結(jié)果大于 0 時返回小于 0 的結(jié)果,比較結(jié)果小于 0 時 返回大于 0 的結(jié)果即可。

要實現(xiàn)多屬性排序,關(guān)鍵就在于比較函數(shù)的實現(xiàn)。根據(jù)以上規(guī)則, 實現(xiàn)多屬性不同方向排序,依然要返回兩個比較項的大小關(guān)系。那么多屬性對象的大小關(guān)系如何確定呢?這個可以分兩步走。

第一步,記錄下兩個排序項按照各個排序?qū)傩约胺较蜻M(jìn)行比較得到的結(jié)果。

var propOrders = { "prop1":"asc", "prop2":"desc", "prop3":"asc"};

function cmp(item1, item2, propOrders) {
    var cps = []; // 用于記錄各個排序?qū)傩缘谋容^結(jié)果,-1 | 0 | 1 。
    var isAsc = true; // 排序方向。     
    for(var p in propOrders) {
        isAsc = propOrders[p] === "asc";
        if(item1[p] > item2[p]) {
            cps.push(isAsc ? 1 : -1);
            break; // 可以跳出循環(huán)了,因為這里就已經(jīng)知道 item1 “大于” item2 了。
        } else if(item1[p] === item2[p]) {
            cps.push(0);
        } else {
            cps.push(isAsc ? -1 : 1);
            break; // 可以跳出循環(huán),item1 “小于” item2。
        }        
    }     
    
    /*
     .
     .
     .
    */
}

第二步,根據(jù)各排序?qū)傩员容^結(jié)果綜合判斷得出兩個比較項的最終大小關(guān)系。

    /* 
     .
     .
     . 
    */
    
    for(var j = 0; j < cps.length; j++) {
        if(cps[j] === 1 || cps[j] === -1) {
            return cps[j];
        }
    }
    return 0;

有了上述思路后,實現(xiàn)整個比較函數(shù)就容易了,下面是比較函數(shù)的完整JavaScript代碼:

比較函數(shù)
function SortByProps(item1, item2) {
    "use strict";
    var props = [];
    for (var _i = 2; _i < arguments.length; _i++) {
        props[_i - 2] = arguments[_i];
    }
        
    var cps = []; // 存儲排序?qū)傩员容^結(jié)果。
    // 如果未指定排序?qū)傩?,則按照全屬性升序排序。    
    var asc = true;
    if (props.length < 1) {
        for (var p in item1) {
            if (item1[p] > item2[p]) {
                cps.push(1);
                break; // 大于時跳出循環(huán)。
            } else if (item1[p] === item2[p]) {
                cps.push(0);
            } else {
                cps.push(-1);
                break; // 小于時跳出循環(huán)。
            }
        }
    } else {
        for (var i = 0; i < props.length; i++) {
            var prop = props[i];
            for (var o in prop) {
                asc = prop[o] === "asc";
                if (item1[o] > item2[o]) {
                    cps.push(asc ? 1 : -1);
                    break; // 大于時跳出循環(huán)。
                } else if (item1[o] === item2[o]) {
                    cps.push(0);
                } else {
                    cps.push(asc ? -1 : 1);
                    break; // 小于時跳出循環(huán)。
                }
            }
        }
    }        
         
    for (var j = 0; j < cps.length; j++) {
        if (cps[j] === 1 || cps[j] === -1) {
            return cps[j];
        }
    }
    return 0;          
}
測試用例
    // -------------測試用例------------------------------
    
    var items = [   { name: "Edward", value: 21 },
                    { name: "Sharpe", value: 37 },
                    { name: "And", value: 45 },
                    { name: "Edward", value: -12 },
                    { name: "Magnetic", value: 21 },
                    { name: "Zeros", value: 37 }
                ];
                
    function test(propOrders) {
        items.sort(function (a, b) {
            return SortByProps(a, b, propOrders);
        });
        console.log(items);
    }
    
    function testAsc() {
        test({ "name": "asc", "value": "asc" });
    }
    
    function testDesc() {
        test({ "name": "desc", "value": "desc" });
    }
    
    function testAscDesc() {
        test({ "name": "asc", "value": "desc" });
    }
    
    function testDescAsc() {
        test({ "name": "desc", "value": "asc" });
    }
實測效果

http://jsfiddle.net/Stronger/nktL5cwa/10

TypeScript代碼
/**
** 排序方向。
*/
type Direct = "asc" | "desc";

/**
** 排序?qū)傩浴?** 
** @interface IPropertyOrder
*/
interface IPropertyOrder {            
    [name: string] : Direct;
}

/**
** 簡單名/值對象。
** 
** @interface ISimpleObject
*/
interface ISimpleObject {
    [name: string] : string | number | boolean;
}

/**
** 對簡單的名/值對象按照指定屬性和排序方向進(jìn)行排序(根據(jù)排序?qū)傩约芭判蚍较颍?** 對兩個項依次進(jìn)行比較,并返回代表排序位置的值)。
** 
** @template T 簡單的名/值對象。
** @param {T} item1 排序比較項1。
** @param {T} item2 排序比較項2。
** @param {...IPropertyOrder[]} props 排序?qū)傩浴?** @returns 若項1大于項2返回1,若項1等于項2返回0,否則返回-1。
*/
function SortByProps
(item1: T, item2: T, ...props: IPropertyOrder[]) {
    "use strict";
    var cps: Array = []; // 存儲排序?qū)傩员容^結(jié)果。
    // 如果未指定排序?qū)傩裕瑒t按照全屬性升序排序。    
    var asc = true;
    if (props.length < 1) {
        for (var p in item1) {
            if (item1[p] > item2[p]) {
                cps.push(1);
                break; // 大于時跳出循環(huán)。
            } else if (item1[p] === item2[p]) {
                cps.push(0);
            } else {
                cps.push(-1);
                break; // 小于時跳出循環(huán)。
            }
        }
    } else { // 按照指定屬性及升降方向進(jìn)行排序。
        for (var i = 0; i < props.length; i++) {
            var prop = props[i];
            for (var o in prop) {
                asc = prop[o] === "asc";
                if (item1[o] > item2[o]) {
                    cps.push(asc ? 1 : -1);
                    break; // 大于時跳出循環(huán)。
                } else if (item1[o] === item2[o]) {
                    cps.push(0);
                } else {
                    cps.push(asc ? -1 : 1);
                    break; // 小于時跳出循環(huán)。
                }
            }
        }
    }

    for (var j = 0; j < cps.length; j++) {
        if (cps[j] === 1 || cps[j] === -1) {
            return cps[j];
        }
    }
    return 0;    
}
使用場景及局限性

在前端使用JavaScript實現(xiàn)多屬性排序,減少了對服務(wù)器端的請求,減輕服務(wù)器端的計算壓力,但是也僅適用于只需要對本地數(shù)據(jù)進(jìn)行排序的情形。如果需要對整個數(shù)據(jù)集進(jìn)行多屬性排序,最終還是要在服務(wù)器端的數(shù)據(jù)庫層面上進(jìn)行。

如果你有更好的實現(xiàn)方式,歡迎留言交流。

本文章版權(quán)歸作者本人所有,轉(zhuǎn)載請注明出處。: )

參考資料

JavaScript MDN - Array.prototype.sort : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79669.html

相關(guān)文章

  • JavaScript 處理數(shù)組函數(shù)總結(jié)

    摘要:從而將傳入的數(shù)組誤判為非數(shù)組。返回值把指定的值添加到數(shù)組后的新長度。方法用于刪除并返回數(shù)組的最后一個元素返回值的最后一個元素。如果數(shù)組已經(jīng)為空,則不改變數(shù)組,并返回值。 JavaScript的array可以包含任意數(shù)據(jù)類型,并通過索引來訪問每個元素。 1、檢測數(shù)組:instanceof、slice()、Array.isArray() 檢測一個對象是不是數(shù)組的三種方法:(1)方法一:i...

    instein 評論0 收藏0
  • 前端實用資源整理

    摘要:事件的響應(yīng)分區(qū)為三個階段捕獲目標(biāo)冒泡階段。綁定的多個事件會被覆蓋,后者覆蓋前者。再用轉(zhuǎn)換成數(shù)值表示。如實際數(shù)量為,則展示為項目中使用過濾器做的處理可以抽取方法的,調(diào)整相關(guān),可以獲取指定位數(shù)的縮寫。 CSS html5中a的download屬性 定義和用法download 屬性定義下載鏈接的地址或指定下載文件的名稱。文件名稱沒有限定值,瀏覽器會自動在文件名稱末尾添加該下載文件的后綴 (...

    Gu_Yan 評論0 收藏0
  • 前端實用資源整理

    摘要:事件的響應(yīng)分區(qū)為三個階段捕獲目標(biāo)冒泡階段。綁定的多個事件會被覆蓋,后者覆蓋前者。再用轉(zhuǎn)換成數(shù)值表示。如實際數(shù)量為,則展示為項目中使用過濾器做的處理可以抽取方法的,調(diào)整相關(guān),可以獲取指定位數(shù)的縮寫。 CSS html5中a的download屬性 定義和用法download 屬性定義下載鏈接的地址或指定下載文件的名稱。文件名稱沒有限定值,瀏覽器會自動在文件名稱末尾添加該下載文件的后綴 (...

    wslongchen 評論0 收藏0
  • JavaScript 實現(xiàn)數(shù)組更多的高階函數(shù)

    摘要:實現(xiàn)數(shù)組更多的高階函數(shù)吾輩的博客原文場景雖說人人平等,但有些人更加平等。若是有一篇適合萌新閱讀的自己實現(xiàn)數(shù)組更多操作的文章,情況或許會發(fā)生一些變化。類似于的初始值,但它是一個函數(shù),避免初始值在所有分組中進(jìn)行累加。 JavaScript 實現(xiàn)數(shù)組更多的高階函數(shù) 吾輩的博客原文: https://blog.rxliuli.com/p/fc... 場景 雖說人人平等,但有些人更加平等。 為...

    aervon 評論0 收藏0
  • MongoDB指南---11、使用復(fù)合索引、$操作符如何使用索引、索引數(shù)組、索引基數(shù)

    摘要:操作符如何使用索引有一些查詢完全無法使用索引,也有一些查詢能夠比其他查詢更高效地使用索引。有時能夠使用索引,但是通常它并不知道要如何使用索引。索引對象和數(shù)組允許深入文檔內(nèi)部,對嵌套字段和數(shù)組建立索引。 上一篇文章:MongoDB指南---10、索引、復(fù)合索引 簡介下一篇文章:MongoDB指南---12、使用explain()和hint()、何時不應(yīng)該使用索引 1、使用復(fù)合索引 在多...

    saucxs 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<