オブジェクトを格納した配列に対して,オブジェクトの特定のプロパティを基準にソートする方法を紹介します。
この配列を age でソートしたい
const arr = [
{name: 'David', age: 25},
{name: 'Bob', age: 30},
{name: 'John', age: 25},
{name: 'Tom', age: 37},
{name: 'Rachel', age: 28},
{name: 'Sam', age: 40},
{name: 'Alice', age: 25},
];
結論
const arr = [
{name: 'David', age: 25},
{name: 'Bob', age: 30},
{name: 'John', age: 25},
{name: 'Tom', age: 37},
{name: 'Rachel', age: 28},
{name: 'Sam', age: 40},
{name: 'Alice', age: 25},
];
const newArr = [...arr].sort((a, b) => (a.age > b.age) ? 1 : -1);
console.log(newArr);
[
{ name: 'Alice', age: 25 },
{ name: 'John', age: 25 },
{ name: 'David', age: 25 },
{ name: 'Rachel', age: 28 },
{ name: 'Bob', age: 30 },
{ name: 'Tom', age: 37 },
{ name: 'Sam', age: 40 }
]
age が同じ場合は name でソート
const arr = [
{name: 'David', age: 25},
{name: 'Bob', age: 30},
{name: 'John', age: 25},
{name: 'Tom', age: 37},
{name: 'Rachel', age: 28},
{name: 'Sam', age: 40},
{name: 'Alice', age: 25},
];
const newArr = [...arr].sort((a, b) => (a.age > b.age) ? 1 : (a.age === b.age) ? ((a.name > b.name) ? 1 : -1) : -1);
console.log(newArr);
[
{ name: 'Alice', age: 25 },
{ name: 'David', age: 25 },
{ name: 'John', age: 25 },
{ name: 'Rachel', age: 28 },
{ name: 'Bob', age: 30 },
{ name: 'Tom', age: 37 },
{ name: 'Sam', age: 40 }
]
文字列の大小比較は辞書順ですが「大文字は小文字より小さい」などの直感的にわからない規則もあるので注意が必要です。
解説
MDN Web Docs の Array.prototype.sort() を読むのが早いです。
比較関数 compare(a, b) の使い方を簡単に言うと
a, b の順 → -1
b, a の順 → 1
コールバック関数の処理部分が少しややこしいです。
(a.age > b.age) ? 1 : (a.age === b.age) ? ((a.name > b.name) ? 1 : -1) : -1
if文で書くとこうなります(分かりやすいように冗長な記述にしています)。
if(a.age > b.age){
return 1;
}else{
if(a.age === b.age){
if(a.name > b.name){
return 1;
}else{
return -1;
}
}else{
return -1;
}
}
蛇足(配列のコピーについて)
sort() は配列そのものを変更する破壊的なメソッドです。
元の配列を維持するために [...arr] とコピーしてから使いました。
配列のコピーは arr.slice() や arr.concat() でもできます。
但し,いずれのコピーも内部のオブジェクトは shallow copy であることに注意してください。
const arr = [
{name: 'David', age: 25},
{name: 'Bob', age: 30},
{name: 'John', age: 25},
{name: 'Tom', age: 37},
{name: 'Rachel', age: 28},
{name: 'Sam', age: 40},
{name: 'Alice', age: 25},
];
const newArr = [...arr]; // 配列のコピーを作成
newArr[0].name = 'Hello'; // 'David' を 'Hello' に変更
console.log(arr);
[
{ name: 'Hello', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'John', age: 25 },
{ name: 'Tom', age: 37 },
{ name: 'Rachel', age: 28 },
{ name: 'Sam', age: 40 },
{ name: 'Alice', age: 25 }
]
オブジェクトを deep copy したい時は,lodash の cloneDeep() を使うのがおすすめです。