欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2016年06月15日 14:09:46   作者:天羽飛龍  
這篇文章主要介紹了JavaScript對象數(shù)組如何按指定屬性和排序方向進(jìn)行排序的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

引子

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

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

后端排序

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

數(shù)據(jù)庫層面實(shí)現(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ū)用鎸?shí)現(xiàn)就是使用PHP、Java、.NET(C#/VB)這些后端服務(wù)語言來實(shí)現(xiàn)對數(shù)據(jù)的排序。以ASP.NET C# 為例,因?yàn)镃#中的LINQ內(nèi)置了對集合類型的諸多操作,并且支持多屬性排序,所以使用LINQ能夠很方便的實(shí)現(xiàn)此目的——from f in foos orderby f.Name descending, f.Num ascending select f(可以發(fā)現(xiàn)LINQ的排序語法幾乎與SQL的一模一樣)。如果其它語言沒有內(nèi)置類似的支持,則按照排序算法來實(shí)現(xiàn),這是通用的,與編程語言無關(guān)。

前端排序

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

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

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

sort函數(shù)原型

// 對數(shù)組的元素做原地的排序,并返回這個(gè)數(shù)組。
// 默認(rèn)按照字符串的Unicode碼位點(diǎn)(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)換為字符串的諸個(gè)字符并按照Unicode位點(diǎn)順序排序。例如,"Cherry"會被排列到"banana"之前。當(dāng)對數(shù)字進(jìn)行排序的時(shí)候, 9 會出現(xiàn)在 80 之前,因?yàn)樗麄儠缺晦D(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 時(shí)返回小于 0 的結(jié)果,比較結(jié)果小于 0 時(shí) 返回大于 0 的結(jié)果即可。

要實(shí)現(xiàn)多屬性排序,關(guān)鍵就在于比較函數(shù)的實(shí)現(xiàn)。根據(jù)以上規(guī)則, 實(shí)現(xiàn)多屬性不同方向排序,依然要返回兩個(gè)比較項(xiàng)的大小關(guān)系。

那么多屬性對象的大小關(guān)系如何確定呢?這個(gè)可以分兩步走。

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

var propOrders = { "prop1":"asc", "prop2":"desc", "prop3":"asc"};
function cmp(item1, item2, propOrders) {
var cps = []; // 用于記錄各個(gè)排序?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)了,因?yà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é)果綜合判斷得出兩個(gè)比較項(xiàng)的最終大小關(guān)系。

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

有了上述思路后,實(shí)現(xiàn)整個(gè)比較函數(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; // 大于時(shí)跳出循環(huán)。
} else if (item1[p] === item2[p]) {
cps.push(0);
} else {
cps.push(-1);
break; // 小于時(shí)跳出循環(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; // 大于時(shí)跳出循環(huán)。
} else if (item1[o] === item2[o]) {
cps.push(0);
} else {
cps.push(asc ? -1 : 1);
break; // 小于時(shí)跳出循環(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" });
} 
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ū)傩约芭判蚍较颍?
** 對兩個(gè)項(xiàng)依次進(jìn)行比較,并返回代表排序位置的值)。
** 
** @template T 簡單的名/值對象。
** @param {T} item1 排序比較項(xiàng)1。
** @param {T} item2 排序比較項(xiàng)2。
** @param {...IPropertyOrder[]} props 排序?qū)傩浴?
** @returns 若項(xiàng)1大于項(xiàng)2返回1,若項(xiàng)1等于項(xiàng)2返回0,否則返回-1。
*/
function SortByProps<T extends ISimpleObject>
(item1: T, item2: T, ...props: IPropertyOrder[]) {
"use strict";
var cps: Array<number> = []; // 存儲排序?qū)傩员容^結(jié)果。
// 如果未指定排序?qū)傩?,則按照全屬性升序排序。 
var asc = true;
if (props.length < 1) {
for (var p in item1) {
if (item1[p] > item2[p]) {
cps.push(1);
break; // 大于時(shí)跳出循環(huán)。
} else if (item1[p] === item2[p]) {
cps.push(0);
} else {
cps.push(-1);
break; // 小于時(shí)跳出循環(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; // 大于時(shí)跳出循環(huán)。
} else if (item1[o] === item2[o]) {
cps.push(0);
} else {
cps.push(asc ? -1 : 1);
break; // 小于時(shí)跳出循環(huán)。
}
}
}
}
for (var j = 0; j < cps.length; j++) {
if (cps[j] === 1 || cps[j] === -1) {
return cps[j];
}
}
return 0; 
}

使用場景及局限性

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

以上所述是小編給大家介紹的JavaScript對象數(shù)組如何按指定屬性和排序方向進(jìn)行排序的全部敘述,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評論