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)

この例では、文字列「10」が文字列「2」よりも前になるため、sort() メソッドは 10 を 2 の前に配置します。

この動作を変更するには、比較関数を sort() メソッドに渡す必要があります。sort() メソッドは、比較関数を使用して要素の順序を決定します。

以下に、比較関数を使用した sort() メソッドの構文を示します

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

この構文では、比較関数は 2 つの引数を受け取り、ソート順を決定する値を返します。

以下に、比較関数の構文を示します

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

compare() 関数は、2 つの引数 ab を受け取ります。sort() メソッドは、compare() 関数の戻り値に基づいて、次の規則に従って要素をソートします。

  • 比較関数が負の数を返す場合、sort() メソッドは ab の前に配置します。
  • 比較関数が正の数を返す場合、sort() メソッドは ba の前に配置します。
  • 比較関数が 0 を返す場合、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)

écureuilzè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 の 3 つのプロパティが含まれています。

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)

出力

この例は、数値の配列を昇順でソートするのと同じように機能します。違いは、2 つのオブジェクトの salary プロパティを比較することです。

文字列プロパティでオブジェクトをソートする

employees 配列を name プロパティで大文字と小文字を区別せずにソートするには、次のように、2 つの文字列を大文字と小文字を区別せずに比較する比較関数を渡します。

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 オブジェクトを作成し、次に 2 つの日付を比較する必要があります。これは、2 つの数値を比較するのと同じです。

これが解決策です

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 配列の要素を Web コンソールに出力します。

出力は、sort() メソッドが各要素を複数回評価することを示しています。たとえば、Amazon は 4 回、Congo は 2 回などです。

配列要素の数が増加すると、パフォーマンスに影響します。

比較関数が実行される回数を減らすことはできません。ただし、比較で実行する必要がある作業を減らすことはできます。この手法は、シュワルツ変換と呼ばれています。

これを実装するには、次の手順に従います

  1. 最初に、map() メソッドを使用して、実際の値を一時配列に抽出します。
  2. 次に、すでに評価(または変換)された要素を使用して、一時配列をソートします。
  3. 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() メソッドは、ソートする前に数値を文字列に変換します。
このチュートリアルは役に立ちましたか?