使用JavaScript的sort方法对字符串数组进行排序

来自菜鸟教程
跳转至:导航、​搜索

Array 原型 上可用的 sort 方法允许您对数组的元素进行排序。 它接受一个可选的回调函数,您可以使用该函数来根据您的特定需求定制排序机制。

对于数字数组,请参阅我们之前关于 排序数字数组 的帖子。


由于 sort 方法的工作原理,对字符串进行排序可能会变得非常固执。

首先,ECMAScript 标准没有指定特定的排序算法,这完全取决于每个浏览器供应商。

其次,套管在分拣时起着至关重要的作用。 为了使排序起作用,必须有顺序排列的东西,这可以通过数字获得 - 数字自然是顺序的(1、2、3、4…)。 当字符串被比较时,它们被转换为它们等效的 Unicode 值 - 不出所料,它们是数字,然后按顺序排序,默认情况下按升序排列。

字符的 Unicode 值

为了获取每个字符的 Unicode 值 - 小写或大写,我们使用 charCodeAt 字符串方法来访问指定字符索引的 字符代码

留在我身边。

我们将从创建有助于获取字符的 unicode 值 以及字符的实用函数开始。 我们将在进行时提及它们。

// get Unicode values of character items in an array
function getCharactersUnicodeValue(characters) {
  const unicodeChart = new Map();
  characters.forEach(character => {
    unicodeChart.set(
      character,
      character.charCodeAt(character.indexOf(character))
    );
  });
  console.table(unicodeChart);
}

// get unicode values of a single character
function getCharacterUnicodeValue(character) {
  const value = character.charCodeAt(character.indexOf(character));
  console.log(value);
}

注意这里使用了 Maps



我们将调用实用程序函数,例如:

getCharactersUnicodeValue("ABCDEFabcdef".split("")); // array of characters: [ 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f' ]
// Result: {character → Unicode Value}
// { A → 65, B → 66, C → 67, D → 68, E → 69, F → 70, a → 97, b → 98, c → 99, d → 100, e → 101, f → 102 }

getCharacterUnicodeValue("A");
// Result: {character → Unicode Value}
// { A → 65 }

这是另一个例子:

const crocodilian = "crOCoDiliaN".split(""); // array of characters i.e [ 'c', 'r', 'O', 'C', 'o', 'D', 'i', 'l', 'i', 'a', 'N' ]

getCharactersUnicodeValue(crocodilian);

// Result: {character → Unicode Value}
// { c → 99, r → 114, O → 79, C → 67, o → 111, D → 68, i → 105, l → 108, a → 97, N → 78 }

请注意,UPPERCASE 字符出现在 小写 字符之前。 它们会依次出现。 排序如下:['Eggs', 'Tail', 'eggs']。 注意 Tail 是如何出现在 eggs 之前的吗? 这是预期的,因为:

getCharactersUnicodeValue(["Eggs", "Tail", "eggs"]);

// Result: {character → Unicode Value}
// { Eggs → 69, Tail → 84, eggs → 101 }
// 84 (T) of Tail comes numerically before 101 (e) of eggs

TL;DR:当字符串仅由相同大小写(全部大写或全部小写)组成时进行排序很容易。 挑战仅来自混合情况。

排序混合大小写字符串

大多数情况下,我们希望我们的 混合大小写字符串数组 被排序,而不管 大小写

const things = [ 'nest', 'Eggs', 'bite', 'gator', 'caYman', 'Grip', 'grips', 'Jaw', 'crocodilian', 'Bayou' ];

最终应排序为:

[ 'Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' ]

并不是:

[ 'Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest' ]

尝试一:没有比较函数

在没有比较函数的情况下调用 sort 方法是行不通的:

things.sort();

// ['Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest']

尝试二:使用比较函数

function sortThings(a, b) {
  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else if (a === b) {
    return 0;
  }
}

然后用 comparison function 排序:

things.sort(sortThings);

// [ 'Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest' ]

尽管如此,它还是行不通。 其实我们还不如不写比较函数

尝试三:使用比较函数和普通案例

问题是排序仍然使用事物数组元素的默认混合大小写我们需要做的是将大小写转换为普通大小写 - 小写 UPPERCASE 都可以。

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();

  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else if (a === b) {
    return 0;
  }
}

或者,使用三元运算符:

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();

  return a > b ? -1 : b > a ? 1 : 0;
}

然后用 comparison function 再次排序:

things.sort(sortThings);

// ['Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' 'eggz']

yippee 它现在可以工作了!


但是等等,还有更多

尽管浏览器供应商有其特定的排序算法,但还是有一些我们应该熟悉的技术。 排序是在 charCodeAt(index) 的基础上完成的。 在两个比较项目几乎相似的情况下,他们的charCodeAt(index)被连续比较。 索引从 0 开始直到有差异。

eggsEggz 为例:

  1. 如果不转换为小写,Eggz 将出现在 eggs 之前,因为 E → 69 的 Unicode 值在 e → 101 之前。
  2. 当转换为类似大小写时(例如小写),我们本质上是在比较 eggseggze → 101e → 101 相等。

跑步:

['Eggz', 'eggs'].sort(sortThings);

// ['eggs', 'Eggz']

正确排序,最后一个字符 s → 115 and z → 122 是确定性字符。

检查如下:

  • [e → 101 ]ggs 和 [e → 101]ggz / 101 === 101,我们移动到下一个字符
  • e[g → 103]gs 和 e[g → 103]gz / 103 === 103,我们移动到下一个字符
  • eg[g → 103]s 和 eg[g → 103]z / 103 === 103,我们移动到下一个字符
  • egg[s → 115] 和 egg[z → 122] / 显然,115 在 122 之前。

等等,决定决斗!

降序

如果您需要按降序排序,只需将比较函数中的 return 1 与 return -1 交换,如下所示:

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  if (a > b) {
    return -1;
  } else if (b > a) {
    return 1;
  } else {
    return 0;
  }
}

或者:

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  return a > b ? -1 : b > a ? 1 : 0;
}

或者只是 reverse 使用 reverse 数组方法的排序数组,这显然将数组反转为相反的序列:

things.sort(sortThings).reverse();

替代方案:使用 localeCompare

虽然 localeCompare 字符串方法可以比较字符而不考虑使用的大小写,但它是字符串方法,因此不能直接在数组上使用。 要使用 localeCompare 字符串方法对我们的 things 数组进行排序,我们将 localeCompare 作为比较函数传递,如下所示:

things.sort((a, b) => a.localeCompare(b));

// [ 'Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' ]

代码一目了然

const things = [
  "nest",
  "Eggs",
  "bite",
  "gator",
  "caYman",
  "Grip",
  "grips",
  "Jaw",
  "crocodilian",
  "Bayou"
];
console.log(`unsorted: ${things.join(", ")}`);

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  return a > b ? 1 : b > a ? -1 : 0;
}

console.log(`sorted:  ${things.sort(sortThings).join(", ")}`);

请记住,继续分类,世界需要它。