一、普通一维数组
js中用 sort()
方法为数组排序。sort()
方法有一个可选参数,是用来确定元素顺序的函数。如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序。如:
var arr = ["a", "A", "c", "B"];
arr.sort();
console.log(arr); // ["A", "B", "a", "c"]
注意:sort()
方法在在原数组上进行排序,不生成副本。
因为字母A、B的ASCII值分别为65、66,而a、b的值分别为97、99,所以上面输出的结果是 ["A", "B", "a", "c"]
。
如果数组元素是数字呢,结果会是怎样?
var arr = [15, 8, 25, 3];
arr.sort();
console.log(arr); // [15, 25, 3, 8]
结果是 [15, 25, 3, 8]
。其实,sort方法会调用每个元素的 toString()
方法,得到字符串,然后再对得到的字符串进行排序。虽然数值15比3大,但在进行字符串比较时"15"则排在"3"前面。显然,这种结果不是我们想要的,这时,sort()
方法的参数就起到了作用,我们把这个参数叫做比较函数。
比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果第一个参数应该位于第二个之后则返回一个正数,如果两个参数相等则返回0。例子:
var arr = [23, 9, 4, 78, 3];
// 比较函数
var compare = function (x, y) {
if (x < y) {
return -1;
} else if (x > y) {
return 1;
} else {
return 0;
}
}
console.log(arr.sort(compare));
结果为 [3, 4, 9, 23, 78]
,返回了我们想要的结果。如果要按降序排序,比较函数写成这样即可:
var compare = function (x, y) {
if (x < y) {
return 1;
} else if (x > y) {
return -1;
} else {
return 0;
}
}
我们并不能用比较函数比较一个不能转化为数字的字符串与数字的顺序:
var arr = ["b", 5];
console.log(arr.sort(compare))
结果是 ["b", 5]
。因为比较函数在比较时,会把先把字符串转化为数字,然后再比较,字符串b不能转化为数字,所以就不能比较大小。然而,当不用比较函数时,会比较ASCII值,所以结果是 [5, "b"]
。
二、数组对象
如果数组项是对象,我们需要根据数组项的某个属性对数组进行排序,要怎么办呢?其实和前面的比较函数也差不多:
var arr = [{name: "zlw", age: 24}, {name: "wlz", age: 25}];
var compare = function (obj1, obj2) {
var val1 = obj1.name;
var val2 = obj2.name;
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
console.log(arr.sort(compare));
输出结果为 [{ name="wlz", age=25}, { name="zlw", age=24}]
,可以看到数组已经按照 name
属性进行了排序。我们可以对上面的比较函数再改造一下:
var compare = function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}
如果想按照 age
进行排序,arr.sort(compare("age"))
即可。
但是对age属性进行排序时需要注意了,如果age属性的值是数字,那么排序结果会是我们想要的。但很多时候我们从服务器传回来的数据中,属性值通常是字符串。现在我把上面的数组改为:
var arr = [{name: "zlw", age: "24"}, {name: "wlz", age: "5"}];
可以看到,我把 age
属性由数字改为了字符串,第二个数组项的 age
值改为了 "5"
。再次调用 arr.sort(compare("age"))
后,结果为:
[Object { name="zlw", age="24"}, Object { name="wlz", age="5"}]
我们的期望是5排在24前面,但是结果不是。这是因为当两个数字字符串比较大小时,会比较它们的ASCII值大小,比较规则是:从第一个字符开始,顺次向后直到出现不同的字符为止,然后以第一个不同的字符的ASCII值确定大小。所以"24"与"5"比较大小时,先比较”2“与"5"的ASCII值,显然”2“的ASCII值比"5"小,即确定排序顺序。
现在,我们需要对比较函数再做一些修改:
var compare = function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
val1 = Number(val1);
val2 = Number(val2);
}
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}
在比较函数中,先把比较属性值转化为数字 Number(val1)
再通过 !isNaN(Number(val1))
判断转化后的值是不是数字(有可能是NaN),转化后的值如果是数字,则比较转换后的值,这样就可以得到我们想要的结果了, 调用 arr.sort(compare("age"))
得到:
[Object { name="wlz", age="5"}, Object { name="zlw", age="24"}]
可以看到,确实是按正确的方式排序了。
以上内容参考:https://www.cnblogs.com/xljzl...
三、排序混合的字母/数字数组
前面我们都已了解数组中的元素将按照ASCII字符顺序进行排序,数组中元素为字母与数字混合时,正常排序是这样的:
var arr = ["a11", "C", "a2", "C4", "C33"];
arr.sort();
console.log(arr); // ["C", "C33", "C4", "a11", "a2"]
我们发现 C33
在 C4 的前面,a11 在a2的前面,可能这种排序方式不能满足一些需求,如果我们的需求是这样:前面字母相同的情况下,后面根据数字的大小来排序。如上面的例子要排成 ["C", "C4", "C33", "a2", "a11"]
这样的结果,我们就需要用到正则了,可以这样来实现:
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
function sortAlphaNum(a, b) {
var aA = a.replace(reA, "");
var bA = b.replace(reA, "");
if (aA === bA) {
var aN = parseInt(a.replace(reN, ""), 10);
var bN = parseInt(b.replace(reN, ""), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return aA > bA ? 1 : -1;
}
}
var arr = ["A1", "A10", "A11", "A12", "A2", "A3", "A4", "B10", "B2", "F1", "F12", "F3"];
arr.sort(sortAlphaNum); // ["A1", "A2", "A3", "A4", "A10", "A11", "A12", "B2", "B10", "F1", "F3", "F12"]
对象数组的实现方案也是类似,只是需要添加需要排序的key名:
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
function sortAlphaNum(a, b) {
var aA = a.name.replace(reA, "");
var bA = b.name.replace(reA, "");
if (aA === bA) {
var aN = parseInt(a.name.replace(reN, ""), 10);
var bN = parseInt(b.name.replace(reN, ""), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return aA > bA ? 1 : -1;
}
}
var singers = [
{ name: 'Ttevie Nicks', band: 'Fleetwood Mac', born: 1948 },
{ name: 'Steven Tyler101', band: 'Aerosmith', born: 1948 },
{ name: 'Steven Tyler11', band: 'The Carpenters', born: 1950 },
{ name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
{ name: 'Stevie Nick', band: 'Fleetwood Mac', born: 1948 },
{ name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
{ name: 'Kurt Coba35in', band: 'Nirvana', born: 1967 },
{ name: 'Kurt Cobai35n', band: 'Nirvana', born: 1967 },
];
console.log(singers.sort(sortAlphaNum));
// 输出结果
// [
// {name: "Kurt Coba35in", band: "Nirvana", born: 1967}
// 1: {name: "Kurt Cobai35n", band: "Nirvana", born: 1967}
// 2: {name: "Kurt Cobain", band: "Nirvana", born: 1967}
// 3: {name: "Steven Tyler11", band: "The Carpenters", born: 1950}
// 4: {name: "Steven Tyler101", band: "Aerosmith", born: 1948}
// 5: {name: "Stevie Nick", band: "Fleetwood Mac", born: 1948}
// 6: {name: "Stevie Nicks", band: "Fleetwood Mac", born: 1948}
// 7: {name: "Ttevie Nicks", band: "Fleetwood Mac", born: 1948}
// ]
对上面的对比函数进行改造:
var sortAlphaNum = function (key) {
return function (a, b) {
var aA = a[key].replace(reA, "");
var bA = b[key].replace(reA, "");
if (aA === bA) {
var aN = parseInt(a[key].replace(reN, ""), 10);
var bN = parseInt(b[key].replace(reN, ""), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return aA > bA ? 1 : -1;
}
}
}
可以直接指定key进行排序:
singers.sort(sortAlphaNum('name'));
这种排序方式和windows文件名/文件夹排序方式基本相同
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。