Array.prototype.sort 是一个原地排序算法,执行后会修改原数组。
看了一些解释,类似于返回正(负)数,谁在谁前面之类的。不容易记,以前我经常随便写一个,运行看看,如果顺序反了就把函数中的俩参数先后顺序换一下。
下面简单说说关于 sort 函数需要记忆哪些知识,才能在业务中直接写不用 debug 一遍过。仅代表个人的想法。
缺省参数
不传参时返回的是升序结果,不是数值意义上的升序,是字符串逐位比较的升序。
[1,2,3,11,12,13,100,120,123].sort()
// => [1, 100, 11, 12, 120, 123, 13, 2, 3]
这和 String.prototype.localeCompare 的逻辑一致。
参数
当传入比较函数作为参数时,可以简单记忆一个数值升序的函数:
(a, b) => a - b
如果需要降序,在参数列表或者函数中颠倒两个参数的位置就行;如果是对象排序,可以解构出两个属性作为参数进行相减。
如果不是排序
由于 sort 函数的作用是原地排序,所以需要原地完成的操作都可以考虑使用它,如果是非数值排序的场景前面的知识可能不太够用。比如 LeetCode 283, 看到原地操作,我就觉得这题就是为了 sort 函数准备的, 你可以先去用 sort 把这道题做做看再回来继续读。
这问题看着挺简单,左项是 0, 右项不是 0,进行交换就行。那就成了俩问题:
- 咋交换
- 谁是左项,谁是右项
下面就直接从这两方面去测试 sort 函数的行为,不再演示错误的尝试了。
交换 / 不交换
先测试下不同返回值是否进行了交换
['a', 'aa', 'aaa', 'zzz', 'zz', 'z'].sort(() => 1)
// => ['a', 'aa', 'aaa', 'zzz', 'zz', 'z'] 没交换
['a', 'aa', 'aaa', 'zzz', 'zz', 'z'].sort(() => 0)
// => ['a', 'aa', 'aaa', 'zzz', 'zz', 'z'] 没交换
['a', 'aa', 'aaa', 'zzz', 'zz', 'z'].sort(() => -1)
// => ['z', 'zz', 'zzz', 'aaa', 'aa', 'a'] 交换了
得到结论,返回负数时会交换,反之不会。
左项 / 右项
['a', 'aa', 'aaa', 'zzz', 'zz', 'z'].sort(console.log)
/* =>
aa a
aaa aa
zzz aaa
zz zzz
z zz
*/
可以得出结论:
array.sort((a, b) => {
// 左项:b, 右项:a
...
}
可以看到俩参数对应数值顺序和直觉上的顺序是反着的。
所以根据前面的测试结果,可以写出这道题的代码:
var moveZeroes = function (nums) {
nums.sort((b, a) => {
// 左项为 0, 右项不为 0,进行交换
if (a == 0 && b !== 0) return -1
});
};
至此,对 sort 的掌握应该可以 hold 住大部分场景了。如果大家发现有什么场景不太够用可以告诉我,我继续编。