JavaScript高级函数之排序sort

简介: 引入排序算法作为各学校算法入门的必修课程,一定给各位留下过深刻的印象。不论是经典的冒泡排序、选择排序,还是当今最高效的快速排序,亦或者是比较有趣的栈排序、桶排序,都凝聚了前人过人的智慧和创造力。不过随着高级语言的出现,似乎当今使用来看我们并不需要每次都自己手码排序算法。像python语言,内置的sorted函数和sort方法允许使用者直接调用来给选定序列排序,并且内部是用c语言基于快速排序编写的,运行效率和占用情况都大大高于我们手码排序算法。JS也是这样一门高级语言,其带有sort函数可以直接给指定序列排序今天就让我们一起了解一下js的sort有什么有趣的地方吧——

引入


排序算法作为各学校算法入门的必修课程,一定给各位留下过深刻的印象。不论是经典的冒泡排序、选择排序,还是当今最高效的快速排序,亦或者是比较有趣的栈排序、桶排序,都凝聚了前人过人的智慧和创造力。

不过随着高级语言的出现,似乎当今使用来看我们并不需要每次都自己手码排序算法。像python语言,内置的sorted函数和sort方法允许使用者直接调用来给选定序列排序,并且内部是用c语言基于快速排序编写的,运行效率和占用情况都大大高于我们手码排序算法。

JS也是这样一门高级语言,其带有sort函数可以直接给指定序列排序

今天就让我们一起了解一下js的sort有什么有趣的地方吧——


1. sort方法调用


前面我们介绍过js中“方法”的概念。本质上是和对象建立关联的函数。sort函数默认和array对象建立了关联。所有的array可以直接调用sort方法来进行排序。我们看看效果——


['juejin', 'aliyun', 'cnds'].sort(); // 输出结果为 ['aliyun', 'cnds', 'juejin']


对字符串的排序是从第一个开始一个个字符比对ASCII码来实现的。a<c<j,所以我们自然就得到了如上的输出结果。如果出现首个字符相同,则比较第二个……以此类推

但要注意,大小写字符的ASCII码是不一样的(如果一样的话电脑怎么区分大小写呢?)所以可能会出现下面的情况——


['Juejin', 'aliyun', 'cnds'].sort(); // 输出结果为 [ 'Juejin','aliyun', 'cnds']


如上结果。J是大写字母,大写字母的ASCII码要在小写之前,因而排在最后的j换成大写J了以后直接排在了最前面。

那么针对数值的排序是怎么样的呢?我们来实践一下


[101, 208, 105, 2000].sort(); // [101, 105, 2000, 208]


结果不是我们想要的数值排序。而仍然是字符串排序结果。说明在js中,sort会自动把所有元素转化成字符串类型,再按照字符串的比较方式进行排序


2. sort的自定义排序


那么我们要实现数值的排序应该怎么办呢?这时候就要引入我们的sort函数自定义功能了。

我们可以在sort()中传入一个自定义函数,构造规则一般如下:

设置两个参数,一般为x,y

用分支语句进行条件判断

如果不符合预期排序前后顺序的则return 1,符合预期顺序的return -1,相等时return 0。

举个具体的例子吧。如果我们希望按照数值排序,则可以采用如下代码构造函数


var arr = [101, 208, 105, 2000];
arr.sort(function (x, y) {
    if (x < y) {
        return -1;
    }
    if (x > y) {
        return 1;
    }
    return 0;
}); // [101, 105, 208, 2000]


设置function之后sort便不会直接把array的所有元素转为字符串,而是直接针对函数里的规则进行判断。

在这里我们发现,如果x<y,这说明了小的在前面,符合了我们的预期,于是return -1。x>y是大的数在前面,不符合预期,我们返回1。

其余情况为相等,我们返回0(其实不设置这个也可以,因为相等的数不需要改变顺序。但为了考虑xy相等的情况,如果我们舍弃了return 0,最好把等号放到条件判断里,如把x<y改成x<=y或者把x>y改成x>=y)

在这里不设置return 0并没有任何影响:


image.png


我们发现输出值是正确的。

那么请问,倒序的时候应该如何设置呢?

其实很简单,只要把“预期顺序”改变就行,之前我们希望x,y这种顺序是x<y时出现的,所以在x<y的时候return了-1,而现在我们改变了预期,便要让x<y的时候return 1。x>y的情况亦然。修改代码后如下:


arrr = [10, 20, 10, 1, 2, 20, 20, 26, 80]
arrr.sort(function (x, y) {
    if (x <= y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
});
console.log(arrr);


image.png

image.png


输出正常。


3. 关于sort的一点思考


很多人一看到这个x,y相比较,就感觉像是冒泡排序

其实这样理解是不对的,冒泡是效率非常低的,业内不会设计由冒泡来作为排序函数的底层逻辑

事实上,js的sort底层原理是由引擎实现的,可能有涉及timsort、快排等多种排序算法。我们作为js使用者、前端工程师而非算法设计师不必细究。有兴趣可以作为拓展知识了解。

此外,关于-1和1,其实在实际使用中可以直接用任意负数、正数替代。这样一来,对数值的排序可以简化成:


arrr = [10, 20, 10, 1, 2, 20, 20, 26, 80]
arrr.sort(function (x, y) {
    return x-y
});
console.log(arrr); 


当x<y的时候,x-y<0,负数,表示符合预期(x小y大,x,y这种x在前y在后的顺序是正确的)。

反之x>y, x-y>0, 正数,不符合预期,因为此时x,y这种大在前小在后的顺序是不应该出现的。

x==y的时候相减为0,0本身也不会影响排序先后,可以忽略。

这就构造了一个升序sort:


image.png

输出正常


还有关于我上面提到的“符合预期”理解法,其实是经过我个人简化后的理解。按照主流理解逻辑,function中x和y的关系应该是这样理解的,个人感觉逻辑上需要绕一绕

sort本身只会升序排序,即从小到大。但什么算小,什么算大是可以由我们决定的。

我们只需要举两个数作为例子,告诉计算机什么情况算小,什么情况算大即可

这个“告诉”的规则是,如果对传入的x,y而言,x<y则返回-1,x>y返回1,x==y返回0.

对于数字而言,我们传入的xy分别代表一个数,如果是升序,则符合默认sort逻辑,无需改动。

但如果是降序,我们需要改变计算机认为的大小逻辑,此时x>y时需要让计算机认为是x<y。

举个例子,我们传入的一串数是2,3,1,希望升序排序。sort会的就是升序,于是我们按照我们的逻辑告诉计算机当x比y小时,你要当作x比y小(比如正常逻辑是1小于3,你就让计算机当作1小于3)。计算机sort升序之后就是1,2,3

当我们传入2,3,1,希望降序排序。但是sort只知道升序啊,那我们要实现降序,就得告诉计算机:当x<y的时候,你要当作x>y呀(比如正常逻辑是1小于3,但你告诉计算机1大于3),于是计算机按照他的“新逻辑”升序排序之后,排出来的结果对我们正常逻辑就是降序的。排出来就是3,2,1

这个“新逻辑”不光可以运用在数上,你可以建立任何的“新逻辑”,比较经典的是我们可以忽略大小写判断字符串大小:


var arr = ['Juejin', 'aliyun', 'cnds'];
arr.sort(function (x, y) {
    x1 = x.toUpperCase();
    y1 = y.toUpperCase();
    if (x1 < y1) {
        return -1;
    }
    if (x1 > y1) {
        return 1;
    }
    return 0;
}); // 输出结果为['aliyun', 'cnds', 'Juejin']


我们相当于告诉了计算机,当x1<y1的时候(也就是所有元素都转化成大写的x和y),我们告诉电脑要此时x和y的关系要当作x<y。反之同理。这就完成了一次对字符不区分大小写的升序。

略有冗长,如果一下子有点难理解,不妨还是用简便理解法。但既然想体验coding之美,不如还是尝试着自己想想吧


相关文章
|
2月前
|
前端开发 JavaScript 算法
使用 JavaScript 数组方法实现排序与去重
【10月更文挑战第21天】通过灵活运用 `sort()` 方法和 `filter()` 方法,我们可以方便地实现数组的排序和去重。同时,深入理解排序和去重的原理,以及根据实际需求进行适当的优化,能够更好地应对不同的情况。可以通过实际的项目实践来进一步掌握这些技巧,并探索更多的应用可能性。
109 59
|
1月前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
42 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
1月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
2月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
3月前
|
JavaScript 前端开发 安全
JavaScript函数详解
JavaScript函数的详细解析,包括函数的定义和调用方式(如一般格式、匿名函数、构造函数、自调用函数、箭头函数和严格模式)、函数参数(arguments对象、可变参数、默认参数值)、闭包的概念和应用实例。
JavaScript函数详解
|
2月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
44 4
|
2月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
21 2
|
2月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
28 5
|
2月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
25 3