JavaScript 数组排序:排序数组元素

摘要:在本教程中,您将学习如何使用 JavaScript 数组 sort() 方法对数字、字符串和对象的数组进行排序。

JavaScript 数组 sort() 方法简介

sort() 方法允许您对 数组 中的元素进行就地排序。它会更改原始数组中元素的位置并返回排序后的数组。

默认情况下,sort() 方法按升序对数组元素进行排序,这意味着它会先将最小值放在最前面,然后将最大值放在最后面。

当您对数字数组进行排序时,sort() 方法会将这些数字转换为字符串,然后比较这些字符串以确定顺序。例如

let numbers = [0, 2, 5, 3, 10];
numbers.sort();
console.log(numbers);Code language: JavaScript (javascript)

输出为

[ 0, 10, 2, 3, 5 ]Code language: JSON / JSON with Comments (json)

在此示例中,sort() 方法将 10 放在 2 之前,因为字符串“10”在字符串“2”之前。

要更改此行为,您需要将比较器函数传递给 sort() 方法。sort() 方法将使用比较器函数来确定元素的顺序。

以下说明了带有比较器函数的 sort() 方法的语法

array.sort(comparator)Code language: CSS (css)

在此语法中,比较器函数接受两个参数并返回一个值,该值决定排序顺序。

以下说明了比较器函数的语法

function compare(a,b) {
  // ...
}Code language: JavaScript (javascript)

compare() 函数接受两个参数 absort() 方法将根据 compare() 函数的返回值对元素进行排序,遵循以下规则

  • 如果比较器函数返回一个负数,则 sort() 方法将 a 放在 b 之前。
  • 如果比较器函数返回一个正数,则 sort() 方法将 b 放在 a 之前。
  • 如果比较器函数返回零,则 sort() 方法认为 a 和 b 相等,并保持它们的位置不变。

因此,要按升序对数字数组进行排序,您可以使用以下比较器函数

let numbers = [0, 2, 5, 3, 10];

numbers.sort(function (a, b) {
  if (a > b) return 1;
  if (a < b) return -1;
  return 0;
});

console.log(numbers);
Code language: JavaScript (javascript)

输出

[ 0, 2, 3, 5, 10 ]Code language: JSON / JSON with Comments (json)

为了使代码更简洁,您可以使用 箭头函数 语法定义比较器函数

let numbers = [0, 2, 5, 3, 10];

numbers.sort((a, b) => {
  if (a > b) return 1;
  if (a < b) return -1;
  return 0;
});

console.log(numbers);
Code language: JavaScript (javascript)

由于数组元素是数字,您可以使代码更短,如下所示

let numbers = [0, 2, 5, 3, 10];
numbers.sort((a, b) => a - b);
console.log(numbers);Code language: JavaScript (javascript)

要按降序对数字数组进行排序,您可以反转比较器函数的结果,如下所示

let numbers = [0, 2, 5, 3, 10];
numbers.sort((a, b) => b - a);
console.log(numbers);Code language: JavaScript (javascript)

输出

[ 10, 5, 3, 2, 0 ]Code language: JSON / JSON with Comments (json)

对字符串数组进行排序

假设您有一个名为 animals 的字符串数组,如下所示

let animals = ['cat', 'dog', 'elephant', 'bee', 'ant'];Code language: JavaScript (javascript)

要按字母顺序对 animals 数组的元素进行升序排序,您可以使用 sort() 方法,而不传递比较函数,如以下示例所示

let animals = ['cat', 'dog', 'elephant', 'bee', 'ant'];
animals.sort();

console.log(animals);Code language: JavaScript (javascript)

输出

[ 'ant', 'bee', 'cat', 'dog', 'elephant' ]Code language: JSON / JSON with Comments (json)

要按降序对 animals 数组进行排序,您需要更改比较器函数的逻辑,并将其传递给 sort() 方法,如以下示例所示。

let animals = ['cat', 'dog', 'elephant', 'bee', 'ant'];

animals.sort((a, b) => {
  if (a > b) return -1;
  if (a < b) return 1;
  return 0;
});

console.log(animals);Code language: JavaScript (javascript)

输出

[ 'elephant', 'dog', 'cat', 'bee', 'ant' ]Code language: JSON / JSON with Comments (json)

假设您有一个包含大小写元素的数组,如下所示

let mixedCaseAnimals = ['Cat', 'dog', 'Elephant', 'bee', 'ant'];Code language: JavaScript (javascript)

要按字母顺序对该数组进行排序,您需要使用自定义比较器函数将所有元素转换为相同的大小写,例如,将所有元素转换为大写进行比较,并将该函数传递给 sort() 方法。

let mixedCaseAnimals = ['Cat', 'dog', 'Elephant', 'bee', 'ant'];

mixedCaseAnimals.sort(function (a, b) {
  let x = a.toUpperCase(),
    y = b.toUpperCase();
  return x == y ? 0 : x > y ? 1 : -1;
});Code language: JavaScript (javascript)

输出

[ 'ant', 'bee', 'Cat', 'dog', 'Elephant' ]Code language: JSON / JSON with Comments (json)

对包含非 ASCII 字符的字符串数组进行排序

sort() 方法对包含 ASCII 字符的字符串可以正常工作。但是,对于包含非 ASCII 字符的字符串,例如 é、è 等,sort() 方法将无法正常工作。例如

let animaux = ['zèbre', 'abeille', 'écureuil', 'chat'];
animaux.sort();

console.log(animaux);Code language: JavaScript (javascript)

输出

[ 'abeille', 'chat', 'zèbre', 'écureuil' ]Code language: JSON / JSON with Comments (json)

该代码返回意外的输出,因为 écureuil 应该在 zèbre 之前。

要解决此问题,您可以使用 String 对象的 localeCompare() 方法以特定语言环境比较字符串,如下所示

let animaux = ['zèbre', 'abeille', 'écureuil', 'chat'];
animaux.sort(function (a, b) {
  return a.localeCompare(b);
});
console.log(animaux);Code language: JavaScript (javascript)

输出

[ 'abeille', 'chat', 'écureuil', 'zèbre' ]Code language: JSON / JSON with Comments (json)

现在,animaux 数组的元素按正确的顺序排列。

按属性对对象数组进行排序

以下是 employee 对象的数组,每个对象包含三个属性:namesalaryhireDate

let employees = [
    {name: 'John', salary: 90000, hireDate: "July 1, 2010"},
    {name: 'David', salary: 75000, hireDate: "August 15, 2009"},
    {name: 'Ana', salary: 80000, hireDate: "December 12, 2011"}
];Code language: JavaScript (javascript)

按数字属性对对象进行排序

以下示例显示了如何按 salary 属性对员工进行升序排序。

let employees = [
  { name: 'John', salary: 90000, hireDate: 'July 1, 2010' },
  { name: 'David', salary: 75000, hireDate: 'August 15, 2009' },
  { name: 'Ana', salary: 80000, hireDate: 'December 12, 2011' },
];

// sort by salary
employees.sort(function (x, y) {
  return x.salary - y.salary;
});

console.table(employees);Code language: JavaScript (javascript)

输出

此示例的工作方式与按升序对数字数组进行排序相同。不同之处在于它比较了两个对象的 salary 属性。

按字符串属性对对象进行排序

要按 name 属性对 employees 数组进行不区分大小写的排序,您可以传递比较两个字符串时不区分大小写的比较函数,如下所示

let employees = [
  { name: 'John', salary: 90000, hireDate: 'July 1, 2010' },
  { name: 'David', salary: 75000, hireDate: 'August 15, 2009' },
  { name: 'Ana', salary: 80000, hireDate: 'December 12, 2011' },
];

employees.sort(function (x, y) {
  let a = x.name.toUpperCase(),
    b = y.name.toUpperCase();
  return a == b ? 0 : a > b ? 1 : -1;
});

console.table(employees);Code language: JavaScript (javascript)

按日期属性对对象进行排序

假设您希望根据每个员工的入职日期对员工进行排序。

入职日期数据存储在员工对象的 hireDate 属性中。但是,它只是一个表示有效日期的字符串,而不是 Date 对象。

因此,要按入职日期对员工进行排序,您首先必须从日期字符串中创建一个有效的 Date 对象,然后比较两个日期,这与比较两个数字相同。

以下为解决方案

let employees = [
  { name: 'John', salary: 90000, hireDate: 'July 1, 2010' },
  { name: 'David', salary: 75000, hireDate: 'August 15, 2009' },
  { name: 'Ana', salary: 80000, hireDate: 'December 12, 2011' },
];

employees.sort(function (x, y) {
  let a = new Date(x.hireDate),
    b = new Date(y.hireDate);
  return a - b;
});

console.table(employees);Code language: JavaScript (javascript)

优化 JavaScript 数组 sort() 方法

sort() 方法会对数组中的每个元素多次调用比较器函数。

请参见以下示例

let rivers = ['Nile', 'Amazon', 'Congo', 'Mississippi', 'Rio-Grande'];

rivers.sort(function (a, b) {
    console.log(a, b);
    return a.length - b.length;
});Code language: JavaScript (javascript)

输出

Amazon Nile
Congo Amazon
Congo Amazon
Congo Nile
Mississippi Congo
Mississippi Amazon
Rio-Grande Amazon
Rio-Grande Mississippi

工作原理

  1. 首先,声明一个名为 rivers 的数组,其中包含著名的河流名称。
  2. 其次,使用 sort() 方法按其元素的长度对 rivers 数组进行排序。每当 sort() 方法调用比较器函数时,我们都会将 rivers 数组的元素输出到网页控制台。

输出显示 sort() 方法会对每个元素进行多次评估,例如,Amazon 4 次,Congo 2 次,等等。

如果数组元素的数量不断增加,它将影响性能。

我们无法减少比较器函数执行的次数。但是,我们可以减少比较器函数需要做的工作。这种技术称为 Schwartzian 变换

要实现这一点,您需要遵循以下步骤

  1. 首先,使用 map() 方法将实际值提取到一个临时数组中。
  2. 其次,对已评估(或转换)元素的临时数组进行排序。
  3. 第三,遍历临时数组以获取排序后的数组。

以下为解决方案

let rivers = ['Nile', 'Amazon', 'Congo', 'Mississippi', 'Rio-Grande'];

// temporary array holds objects with position and length of element
var lengths = rivers.map(function (e, i) {
  return { index: i, value: e.length };
});

// sorting the lengths array containing the lengths of river names
lengths.sort(function (a, b) {
  return +(a.value > b.value) || +(a.value === b.value) - 1;
});

// copy element back to the array
var sortedRivers = lengths.map(function (e) {
  return rivers[e.index];
});

console.log(sortedRivers);Code language: JavaScript (javascript)

输出

[ 'Nile', 'Congo', 'Amazon', 'Rio-Grande', 'Mississippi' ]Code language: JSON / JSON with Comments (json)

摘要

  • sort() 方法对数组元素进行就地排序并返回排序后的数组。
  • sort() 方法会在排序之前将数字转换为字符串。
本教程是否有帮助?