sort
让我们检查一下数组方法的 EMCAScript 规范。该sort
算法迭代地比较数组中的元素对;这些比较产生-1
、1
或0
(分别表示小于、大于或等于),并且每次比较的结果用于构建排序数组。
特别是,我们关注 的“默认”比较情况sort
,其中没有指定比较函数。比较一对x
and时y
:
- 令 xString 为 ToString(x)。
- 设 yString 为 ToString(y)。
- 如果 xString < yString,则返回 -1。
- 如果 xString > yString,则返回 1。
- 返回+0。
ECMAScriptToString
应用于对象时,会调用对象的toString
方法。
x > y
为了阐明and的含义x < y
,我们可以检查 ECMAScript 的抽象关系比较算法,它指定了>
and<
运算符的行为。如果操作数px
和py
都是字符串:
- 令 k 为最小的非负整数,使得 px 中位置 k 处的字符与 py 中位置 k 处的字符不同...
- 令 m 为整数,它是 px 内位置 k 处的字符的代码单元值。
- 令 n 为整数,它是 py 中位置 k 处的字符的代码单元值。
- 如果 m < n,则返回 true。否则,返回假。
这是一个简单的字符串比较,基于字符串中第一个不同位置的字符的 Unicode 代码单元值的比较。
如您所见,该sort
算法将其包含的每个对象元素(使用元素的toString
方法)字符串化,然后比较这些字符串以确定排序。我知道这对您来说似乎很奇怪:如果您的排序数组中只有数组元素,为什么不使用这些子数组的元素来确定排序?这仅仅是因为 EMCAScript 规范选择保持潜在异构数组的默认元素比较非常通用,因为任何类型的元素都可以呈现为字符串。
但是,如果您想要数组下降行为,则可以实现:
var compare_items = function(a,b) {
var result;
if(a instanceof Array && b instanceof Array) {
// iteratively compare items from each array
for(var i=0; i<Math.min(a.length,b.length); ++i) {
result = compare_items(a[i], b[i]);
if(result != 0) { return result; }
}
// if both arrays are equal so far, length is the determining factor
return a.length - b.length;
}
// if the items are both numbers, report their numeric relation
if(typeof a == "number" && typeof b == "number") {
return a - b;
}
// otherwise, fall back to strings
if(a.toString() == b.toString()) { return 0; }
return a.toString() > b.toString() ? 1 : -1;
}
然后,使用此比较器功能,如arr_2d.sort(compare_items);
.
这允许您对任意深度的 N 维数组进行排序。首先我们a[0]...[0][0]
与b[0]...[0][0]
thena[0]...[0][1]
进行比较b[0]...[0][1]
; 然后,如果子数组[0]...[0][*]
证明相等,我们向上移动a[0]...[1][0]
,等等。比较不同维度的数组可能会产生不寻常的结果,因为可以将非数组与比较每个操作数的字符串形式的数组进行比较。
请注意,如果您有一个异构数组,则此函数会产生奇怪的结果:[1, 2, 3, [1,2], [2,3]]
排序为[1, [1,2], 2, [2,3], 3]
. 数组和非数组的排序相对正确,但是数组和非数组以一种不直观的方式分散在其中。