多条件排序

有个这么个要求,给一组数组

  1. var data = [
  2. {a:1,b:2},
  3. {a:2,b:5},
  4. {a:3,b:4},
  5. {a:2,b:7},
  6. {a:1,b:2},
  7. {a:2,b:7},
  8. {a:4,b:8},
  9. {a:2,b:123},
  10. {a:5,b:23},
  11. ]

要求a从小到大排序,a相等的b从大到小排序


首先实现属性a从小到大排序

  1. data.sort(function(a,b) {
  2. return a.a - b.a
  3. })

接着继续掉调用把属性a排序好的数组

  1. data.sort(function(a,b) {
  2. return a.a - b.a
  3. }).sort(function(a,b) {
  4. // 如果a属性相等则进行比较,否则不改变位置
  5. if(a.a === b.a) {
  6. return b.b - a.b
  7. } else {
  8. return -1
  9. }
  10. })
  11. console.log(data)

打印一下,也没问题。本以为就这样能搞定的我,还是图样了。

当我把数组的元素增加多几个的时候:

  1. var data = [
  2. {a:1,b:2},
  3. {a:2,b:5},
  4. {a:3,b:4},
  5. {a:2,b:7},
  6. {a:1,b:2},
  7. {a:2,b:7},
  8. {a:4,b:8},
  9. {a:2,b:123},
  10. {a:5,b:23},
  11. {a:1,b:23},
  12. {a:2,b:55},
  13. {a:4,b:8},
  14. {a:2,b:12},
  15. {a:5,b:33},
  16. ]

问题就来了,使用上面的方法排序,完全得不到预想的结果。

这明明刚才还可以的怎么增加一点数据就完全变样了呢,所谓一言不合看源码。还真是有道理

v8 array部分源码 (搜索“InnerArraySort”)

可以看到该方法首行就备注了

  1. // In-place QuickSort algorithm.
  2. // For short (length <= 10) arrays, insertion sort is used for efficiency.

V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数量小于10的数组使用 InsertionSort,比10大的数组则使用 QuickSort。

快排不像插入排序,从后往前扫相邻的两个元素进行比较,而是找基准,遍历数组,小于基准的放在left,大于基准的放在right,递归

修改后的方法

  1. data.sort((a, b) => {
  2. return a.a === b.a ? ( a.b - b.b ) : a.a - b.a;
  3. })

封装一下

  1. var by = function(name, minor){
  2. return function(o, p) {
  3. var a, b;
  4. a = o[name];
  5. b = p[name];
  6. if (a === b) {
  7. return typeof minor === 'function' ? minor(o,p) : 0;
  8. }
  9. if (typeof a === typeof b) {
  10. return a < b ? -1 : 1;
  11. }
  12. }
  13. }
  14. data.sort(by('age',by('sin')));