当前位置:首页 > 问答 > 正文

数组排序不再难:深入理解sort函数,面试轻松过关

还记得上次面试,面试官让你手写一个排序算法吗?你吭哧吭哧写了半天,结果发现JavaScript自带的sort函数一行代码就搞定了,但别高兴太早,sort函数用起来简单,里面的坑可不少,今天咱们就把它彻底搞明白,让你在面试中遇到这类问题能对答如流。

第一部分:sort函数的基本用法,但你可能一直用错了

很多人以为array.sort()就是按数字从小到大排序,

let arr = [10, 5, 2, 8, 1];
arr.sort();
console.log(arr); // 你猜输出什么?[1, 2, 5, 8, 10]?

错了!实际输出是[1, 10, 2, 5, 8],是不是很意外?这是因为,如果不给sort传参数,它会默认把所有元素先转换成字符串,然后按照字符串的Unicode码点来排序,所以10排在了2的前面,就像“10”和“2”两个单词,比较第一个字符“1”在“2”前面一样。

那怎么正确对数字排序呢?这就需要用到sort的核心——比较函数了。

第二部分:灵魂所在——比较函数(Comparator Function)

比较函数是sort的精髓,它决定了排序的规则,这个函数接收两个参数,通常用ab表示,代表数组中正在比较的两个元素。

sort函数会根据你返回的数字来决定a和b的顺序:

数组排序不再难:深入理解sort函数,面试轻松过关

  • 返回负数(< 0):那么a会排在b的前面
  • 返回正数(> 0):那么a会排在b的后面
  • 返回 0:表示a和b相等,相对位置不变。

记住这个规则,所有排序都难不倒你。

数字升序排序(从小到大)

想让数字从小到大排,思路是:如果a - b是负数,说明a比b小,那么a就应该排在b前面,正好符合规则。

let arr = [10, 5, 2, 8, 1];
arr.sort(function(a, b) {
  return a - b; // 升序的关键
});
console.log(arr); // 现在对了:[1, 2, 5, 8, 10]

数字降序排序(从大到小)

那从大到小呢?很简单,用b - a,如果b - a是正数,说明b比a小,但根据规则,返回正数时a要排在b的后面,也就是更大的数a被排到了后面,更小的数b被排到了前面,整体就是从大到小。

let arr = [10, 5, 2, 8, 1];
arr.sort(function(a, b) {
  return b - a; // 降序的关键
});
console.log(arr); // [10, 8, 5, 2, 1]

第三部分:实战进阶,面试官爱问的这些你都会吗?

数组排序不再难:深入理解sort函数,面试轻松过关

光会排数字可不够,面试官喜欢考更实际的场景。

排序对象数组

比如有一个学生数组,每个学生有姓名和分数,要按分数从高到低排名。

let students = [
  { name: '小明', score: 90 },
  { name: '小红', score: 95 },
  { name: '小刚', score: 87 }
];
// 按分数降序排列
students.sort(function(a, b) {
  return b.score - a.score;
});
console.log(students);
// 输出:
// [ { name: '小红', score: 95 },
//   { name: '小明', score: 90 },
//   { name: '小刚', score: 87 } ]

多条件排序

如果分数一样怎么办?面试官会接着问:如果分数相同,再按姓名的拼音首字母顺序排。

这时,我们在比较函数里先判断分数是否相等,如果不相等,按分数排;如果相等,再比较姓名。

数组排序不再难:深入理解sort函数,面试轻松过关

let students = [
  { name: '小明', score: 90 },
  { name: '小红', score: 95 },
  { name: '小张', score: 90 } // 新增一个也是90分的同学
];
students.sort(function(a, b) {
  // 首要条件:按分数降序
  if (b.score !== a.score) {
    return b.score - a.score;
  } else {
    // 次要条件:分数相同时,按姓名升序排列
    // 比较字符串,直接用 > 或 <
    if (a.name < b.name) {
      return -1; // a排在b前面
    }
    if (a.name > b.name) {
      return 1; // a排在b后面
    }
    return 0; // 名字也一样(虽然不太可能)
  }
});
console.log(students);
// 输出:小红(95) -> 小张(90) -> 小明(90)
// 因为“小张”的拼音首字母"Z"在“小明”的"X"后面,但按字母顺序排升序,X在前,Z在后,所以小明应该在小张前面?这里注意中文排序比较复杂,通常会用localeCompare,这里只是示意逻辑。

更准确的中文字符串比较应该用localeCompare

// 接上例,次要条件部分可以简写为:
else {
  return a.name.localeCompare(b.name); // 用于正确比较中文字符串
}

第四部分:记住这些,避免踩坑

  1. sort会改变原数组:它是“原地排序”,直接修改原数组,而不是返回一个新数组,如果你需要保留原数组,记得先拷贝一份。

    let newArr = [...arr].sort((a, b) => a - b); // 使用扩展运算符拷贝
  2. 关于稳定性:现代的浏览器和Node.js环境中的sort算法基本都是稳定排序,意思是,如果两个元素比较值相等,排序后它们的相对顺序会和排序前一样,这在多条件排序时非常重要,面试时如果被问到,你可以自信地说“是稳定的”。

总结一下

sort函数的核心就是那个比较函数,记住它的返回值规则:

  • a - b -> 升序
  • b - a -> 降序

遇到复杂对象或多条件排序,就在函数里写好你的比较逻辑,理解了这些,面试中关于数组排序的问题基本上就都能解决了。