【JavaScript】使用 array.sort(() => number) 实现数组的各种排序,支持对象的排序

513 阅读4分钟

前文回顾:
清空数组元素,哪种方式效率更好?【length=0 】VS 【splice(0,len)】

数组如何排序?我们可以使用 sort 来实现,如果数组成员是对象的话,如何排序呢?

数字

我们先看看数组成员是数字的情况。

默认排序

  const arrNumber = [1,20,11,25,81,3,8,10,11]

  arrNumber.sort()
  console.log('arrNumber-sort() :', arrNumber)

sort() 没有传递参数的话,就是默认排序,那么排序规则是按照数字吗?测试了一下发现,并不是按照数字,而是按照字符来排序的。

看看结果:

arrNumber-sort() : (9) [1, 10, 11, 11, 20, 25, 3, 8, 81]

先判断第一位,然后判断第二位,于是1开头的在前,后面是2开头,3开头。

升序

那么如果我们想按照数字排序怎么办?可以使用参数:

 arrNumber.sort((num, next) => num - next )

前一个数和后一个数相减,按照结果进行排序,这样就是从小到大的排序。

看看结果:

arrNumber- num -> next: (9) [1, 3, 8, 10, 11, 11, 20, 25, 81]

倒序

如果想倒序怎么办?倒过来减就行

 arrNumber.sort((num, next) => -num + next )

应该写成 next - num 的,但是我懒,直接改符号多简单。

看看结果:

arrNumber- next -> num: (9) [81, 25, 20, 11, 11, 10, 8, 3, 1]

字符串

字符串排序会如何呢?

默认排序

 const arrString = ['1','11','a', 'v', '8a1', 'a3', '汉字', '大', '小', 'c','22']

看看结果:

 arrString-sort() : (11) ["1", "11", "22", "8a1", "a", "a3", "c", "v", "大", "小", "汉字"]

sort() 默认排序,按照数字、英文、汉字的顺序排列。汉字好像不是按照拼音排序。

使用减法

尝试减法的时候,会出现提示:算术运算必须是 any、number、bigint或者枚举,但是程序可以运行,而且没有报错。好神奇的js。

arrString.sort((num, next) => num - next )
arrString.sort((num, next) => -num + next )

看看结果:

 arrString- num -> next: (11) ["1", "11", "22", "8a1", "a", "a3", "c", "v", "大", "小", "汉字"]
 arrString- next -> num: (11) ["22", "11", "1", "8a1", "a", "a3", "c", "v", "大", "小", "汉字"]

对比一下,只影响数字内部的排序,其他不影响。可能是先进行转换,转换失败的话,按照默认的来。

转换为 ASCII 再排序

字符串不能做减法,那么转换一下呢?

arrString.sort((num, next) => num.charCodeAt(0) - next.charCodeAt(0) )
arrString.sort((num, next) => -num.charCodeAt(0) + next.charCodeAt(0) )

看看结果:

charCodeAt- num -> next: (11) ["11", "1", "22", "8a1", "a", "a3", "c", "v", "大", "小", "汉字"]
charCodeAt- next -> num: (11) ["汉字", "小", "大", "v", "c", "a", "a3", "8a1", "22", "11", "1"]

结果很明显,可以按照第一个字符的ASCII来正序或者倒序。所以默认排序,是按照ASCII排序的。

这里只获取了第一位,没有考虑后面的,所以排序并不完全符合预期。

对象

现在我们使用数组,往往会往里面放对象,那么对象如何排序呢?

按照一个属性排序

我们先看看按照一个字段排序的方式:

  const person = [
    { name: '一', age: 30  },
    { name: '二', age: 18  },
    { name: '三', age: 6  },
    { name: '四', age: 63  },
    { name: '五', age: 35  }
  ]
  person.sort((person, next) => person.age - next.age )
  console.log('arrObject - 年龄正序 :\n', person)

按照年龄从小到大排序,看看结果:

 person - 年龄正序 :

1.  1.  0: {name"三"age6}
    1.  1: {name"二"age18}
    1.  2: {name"一"age30}
    1.  3: {name"五"age35}
    1.  4: {name"四"age63}
    1.  length5
    1.  __proto__Array(0)

测试成功!

按照多个属性排序

那么能不能按照多个字段排序呢?

   const person = [
    { name: '一', age: 30, score: 20  },
    { name: '二', age: 30, score: 24  },
    { name: '三', age: 6, score: 10  },
    { name: '四', age: 63, score: 220  },
    { name: '五', age: 35, score: 280  }
  ]
  // 第一位扩大一千倍
  const order = (person: any) => {
    return person.age * 1000 + person.score
  }
  
  person.sort((person, next) => order(person) - order(next) )
  console.log('arrObject - 先按年龄后按积分 :\n', person)

根据数值的范围,扩大第一位、第二位、第三位......,然后在做减法。

看看结果:

arrObject - 先按年龄后按积分 :
1.     {name"三"age6score10}
1.  1: {name"一"age30score20}
1.  2: {name"二"age30score24}
1.  3: {name"五"age35score280}
1.  4: {name"四"age63score220}
 

这样不止是两个字段,多个字段也可以。

如果数值太大溢出怎么办?

那就先减再扩大:

  const order2 = (person: any, next: any) => {
    return (person.age - next.age) * 1000 + (person.score - next.score)
  }

第一个字段升序,第二个字段降序咋办?

那就先减后加呗

  const order3 = (person: any, next: any) => {
    return (person.age - next.age) * 1000 + (-person.score + next.score)
  }