JavaScript對象數組如何按指定屬性和排序方向進行排序,javascript數組

來源:互聯網
上載者:User

JavaScript對象數組如何按指定屬性和排序方向進行排序,javascript數組

引子

在以資料為中心的資訊系統中,以表格形式展示資料是在常見不過的方式了。對資料進行排序是必不可少的功能。排序可以分為按單個欄位排序和按多個欄位不同排序方向排序。單欄位排序局限性較大,不能滿足使用者對資料的關注點變化的需求,而多欄位排序就可以較好的彌補這個缺陷。

多欄位排序,實現的方式從大的層面上可以分為後端實現和前端實現。

後端排序

後端實現排序可以在資料庫層面實現或者在應用程式層面實現。

資料庫層面實現多欄位排序非常簡單,使用SQL的排序指令“Order By”即可——Order By field1 asc, field2 desc, field3 asc -- ...。
應用程式層面是指Web應用程式層(這裡不討論C/S架構),比如PHP、Java Web、ASP.NET等。應用程式層面實現就是使用PHP、Java、.NET(C#/VB)這些後端服務語言來實現對資料的排序。以ASP.NET C# 為例,因為C#中的LINQ內建了對集合類型的諸多操作,並且支援多屬性排序,所以使用LINQ能夠很方便的實現此目的——from f in foos orderby f.Name descending, f.Num ascending select f(可以發現LINQ的排序文法幾乎與SQL的一模一樣)。如果其它語言沒有內建類似的支援,則按照排序演算法來實現,這是通用的,與程式設計語言無關。

前端排序

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

不過好在“sort”方法預留了自訂排序的介面,可以實現想要的排序方式。

來看看數組的“sort”方法是怎樣的。

sort函數原型

// 對數組的元素做原地的排序,並返回這個數組。// 預設按照字串的Unicode碼位點(code point)排序。Array.prototype.sort([compareFunction]:number); // number:-1 | 0 | 1。// 典型的比較函數(升序排序)。function compareFunction(item1, item2) {if(item1 > item2) {return 1; // 如果是降序排序,返回-1。}else if(item1 === item2) {return 0;}else {return -1; // 如果是降序排序,返回1。}}

說明:如果沒有指明compareFunction,那麼元素會被轉換為字串的諸個字元並按照Unicode位點順序排序。例如,"Cherry"會被排列到"banana"之前。當對數字進行排序的時候, 9 會出現在 80 之前,因為他們會先被轉換為字串,而 "80" 比 "9" 要靠前。

•如果 compareFunction(a, b) 小於 0 ,那麼 a 會被排列到 b 之前;

•如果 compareFunction(a, b) 等於 0 ,a 和 b

的相對位置不變。備忘:ECMAScript標準並不保證這一行為,而且也不是所有瀏覽器都會遵守(例如 Mozilla 在 2003
年之前的版本);

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

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

註:以上規則得出的排序結果是升序的,如果想要得到降序的結果,則在比較結果大於 0 時返回小於 0 的結果,比較結果小於 0 時 返回大於 0 的結果即可。

要實現多屬性排序,關鍵就在於比較函數的實現。根據以上規則, 實現多屬性不同方向排序,依然要返回兩個比較項的大小關係。

那麼多屬性對象的大小關係如何確定呢?這個可以分兩步走。

第一步,記錄下兩個排序項按照各個排序屬性及方向進行比較得到的結果。

var propOrders = { "prop1":"asc", "prop2":"desc", "prop3":"asc"};function cmp(item1, item2, propOrders) {var cps = []; // 用於記錄各個排序屬性的比較結果,-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; // 可以跳出迴圈了,因為這裡就已經知道 item1 “大於” item2 了。} else if(item1[p] === item2[p]) {cps.push(0);} else {cps.push(isAsc ? -1 : 1);break; // 可以跳出迴圈,item1 “小於” item2。} } /*...*/}

第二步,根據各排序屬性比較結果綜合判斷得出兩個比較項的最終大小關係。

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

有了上述思路後,實現整個比較函數就容易了,下面是比較函數的完整JavaScript代碼:

比較函數

function SortByProps(item1, item2) {"use strict";var props = [];for (var _i = 2; _i < arguments.length; _i++) {props[_i - 2] = arguments[_i];}var cps = []; // 儲存排序屬性比較結果。// 如果未指定排序屬性,則按照全屬性升序排序。 var asc = true;if (props.length < 1) {for (var p in item1) {if (item1[p] > item2[p]) {cps.push(1);break; // 大於時跳出迴圈。} else if (item1[p] === item2[p]) {cps.push(0);} else {cps.push(-1);break; // 小於時跳出迴圈。}}} 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; // 大於時跳出迴圈。} else if (item1[o] === item2[o]) {cps.push(0);} else {cps.push(asc ? -1 : 1);break; // 小於時跳出迴圈。}}}} 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" });} TypeScript代碼/**** 排序方向。*/type Direct = "asc" | "desc";/**** 排序屬性。** ** @interface IPropertyOrder*/interface IPropertyOrder { [name: string] : Direct;}/**** 簡單名/值對象。** ** @interface ISimpleObject*/interface ISimpleObject {[name: string] : string | number | boolean;}/**** 對簡單的名/值對象按照指定屬性和排序方向進行排序(根據排序屬性及排序方向,** 對兩個項依次進行比較,並返回代表排序位置的值)。** ** @template T 簡單的名/值對象。** @param {T} item1 排序比較項1。** @param {T} item2 排序比較項2。** @param {...IPropertyOrder[]} props 排序屬性。** @returns 若項1大於項2返回1,若項1等於項2返回0,否則返回-1。*/function SortByProps<T extends ISimpleObject>(item1: T, item2: T, ...props: IPropertyOrder[]) {"use strict";var cps: Array<number> = []; // 儲存排序屬性比較結果。// 如果未指定排序屬性,則按照全屬性升序排序。 var asc = true;if (props.length < 1) {for (var p in item1) {if (item1[p] > item2[p]) {cps.push(1);break; // 大於時跳出迴圈。} else if (item1[p] === item2[p]) {cps.push(0);} else {cps.push(-1);break; // 小於時跳出迴圈。}}} 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; // 大於時跳出迴圈。} else if (item1[o] === item2[o]) {cps.push(0);} else {cps.push(asc ? -1 : 1);break; // 小於時跳出迴圈。}}}}for (var j = 0; j < cps.length; j++) {if (cps[j] === 1 || cps[j] === -1) {return cps[j];}}return 0; }

使用情境及局限性

在前端使用JavaScript實現多屬性排序,減少了對伺服器端的請求,減輕伺服器端的計算壓力,但是也僅適用於只需要對本機資料進行排序的情形。如果需要對整個資料集進行多屬性排序,最終還是要在伺服器端的資料庫層面上進行。

以上所述是小編給大家介紹的JavaScript對象數組如何按指定屬性和排序方向進行排序的全部敘述,希望對大家有所協助,如果大家有任何疑問請給我留言,小編會及時回複大家的。在此也非常感謝大家對幫客之家網站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.