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之美,不如还是尝试着自己想想吧


相关文章
|
5月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
219 19
|
7月前
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索
|
8月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9月前
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
185 32
|
8月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
前端开发 JavaScript 算法
使用 JavaScript 数组方法实现排序与去重
【10月更文挑战第21天】通过灵活运用 `sort()` 方法和 `filter()` 方法,我们可以方便地实现数组的排序和去重。同时,深入理解排序和去重的原理,以及根据实际需求进行适当的优化,能够更好地应对不同的情况。可以通过实际的项目实践来进一步掌握这些技巧,并探索更多的应用可能性。
355 59
|
12月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。