Lodash の sortBy で並び替えを自在にコントロール

配列の並び替えは、フロントエンド開発において頻繁に遭遇する処理の一つです。ユーザーの一覧を名前順に表示したり、商品リストを価格順に並べたりと、データを見やすく整理することは良いユーザビリティの基盤となります。
JavaScript 標準の Array.sort() では複雑な並び替えが煩雑になりがちですが、Lodash の sortBy を使えば、驚くほどシンプルで直感的なコードで高度な並び替えが実現できるのです。
今回は、Lodash sortBy の基本的な使い方から応用的なテクニックまで、実際のコード例を交えながら詳しく解説していきます。この記事を読み終える頃には、あらゆる並び替えの要求に柔軟に対応できるようになるでしょう。
背景
JavaScript 標準の Array.sort() の制限
JavaScript の Array.sort() は基本的な並び替えには便利ですが、複雑な条件を扱うときには課題があります。
javascript// 基本的な数値並び替え
const numbers = [3, 1, 4, 1, 5];
numbers.sort((a, b) => a - b); // [1, 1, 3, 4, 5]
しかし、オブジェクトの配列を複数の条件で並び替えようとすると、コードが複雑になってしまいます。
javascript// 複雑になりがちな複数条件並び替え
const users = [
{ name: '田中', age: 25, score: 85 },
{ name: '佐藤', age: 30, score: 90 },
{ name: '鈴木', age: 25, score: 95 },
];
// 年齢順、同年齢なら点数の降順で並び替え
users.sort((a, b) => {
if (a.age !== b.age) {
return a.age - b.age;
}
return b.score - a.score;
});
複雑な並び替えロジックの実装の困難さ
実際の開発では、さらに複雑な並び替えが求められることがあります。
以下の図は、従来の JavaScript での並び替え処理の複雑さを示しています。
mermaidflowchart TD
start[配列データ] --> check1{第1条件の比較}
check1 -->|等しい| check2{第2条件の比較}
check1 -->|異なる| result1[第1条件で並び替え]
check2 -->|等しい| check3{第3条件の比較}
check2 -->|異なる| result2[第2条件で並び替え]
check3 --> result3[第3条件で並び替え]
result1 --> final[並び替え完了]
result2 --> final
result3 --> final
このように、条件が増えるほど分岐処理が複雑になり、コードの可読性と保守性が損なわれてしまいます。
Lodash sortBy が解決する問題
Lodash の sortBy は、これらの課題を解決する強力なツールです。直感的な書き方で複雑な並び替えを実現し、コードの可読性を大幅に向上させます。
javascriptimport { sortBy } from 'lodash';
// 複数条件での並び替えがシンプルに
const sortedUsers = sortBy(users, ['age', 'name']);
図で理解できる要点:
- 複数条件の並び替えが段階的に処理される
- コードの複雑さが大幅に軽減される
- 保守性と可読性が向上する
課題
複数条件での並び替え
実際の開発では、単一の条件だけでなく、複数の条件を組み合わせた並び替えが必要になることがよくあります。
例えば、以下のような要求があったとします:
- 従業員リストを部署別に並び替え
- 同じ部署内では役職順に並び替え
- 同じ役職なら入社年数順に並び替え
ネストしたオブジェクトプロパティでの並び替え
深い階層を持つオブジェクトのプロパティで並び替えをする場合、アクセスパスが複雑になります。
javascriptconst products = [
{
name: 'ノートPC',
specs: { price: { value: 120000, currency: 'JPY' } },
category: { main: 'コンピューター', sub: 'ノートPC' },
},
// その他の商品データ...
];
このような構造で specs.price.value
や category.main
で並び替えをしたい場合、従来の方法では煩雑になってしまいます。
パフォーマンスとコードの可読性の両立
並び替え処理は、特に大量のデータを扱う場合にパフォーマンスが重要になります。しかし、パフォーマンスを追求するあまりコードが複雑になり、保守性が損なわれることがあります。
理想的には、以下の条件を満たす実装が求められます:
- 高いパフォーマンス
- 読みやすく理解しやすいコード
- 変更に強い柔軟な設計
解決策
sortBy の基本構文と使い方
Lodash の sortBy は、非常にシンプルな構文で強力な並び替え機能を提供します。
javascriptimport { sortBy } from 'lodash';
// 基本的な使い方
const result = sortBy(配列, 並び替えの基準);
まずは、最もシンプルな例から見ていきましょう。
javascript// 数値配列の並び替え
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];
const sortedNumbers = sortBy(numbers);
console.log(sortedNumbers); // [1, 1, 2, 3, 4, 5, 6, 9]
javascript// 文字列配列の並び替え
const fruits = ['バナナ', 'りんご', 'オレンジ', 'いちご'];
const sortedFruits = sortBy(fruits);
console.log(sortedFruits); // ['いちご', 'オレンジ', 'バナナ', 'りんご']
オブジェクトの配列を並び替える場合は、プロパティ名を指定します。
javascript// オブジェクト配列の並び替え
const users = [
{ name: '田中', age: 25 },
{ name: '佐藤', age: 30 },
{ name: '鈴木', age: 20 },
];
// 年齢順で並び替え
const sortedByAge = sortBy(users, 'age');
console.log(sortedByAge);
// [{ name: '鈴木', age: 20 }, { name: '田中', age: 25 }, { name: '佐藤', age: 30 }]
関数を使った動的並び替え
sortBy では、プロパティ名の代わりに関数を使用することで、より柔軟な並び替えが可能です。
javascript// 関数を使った並び替え
const products = [
{ name: 'ノートPC', price: 120000 },
{ name: 'スマートフォン', price: 80000 },
{ name: 'タブレット', price: 50000 },
];
// 価格の降順で並び替え(関数を使用)
const sortedByPriceDesc = sortBy(
products,
(product) => -product.price
);
console.log(sortedByPriceDesc);
// 価格の高い順に並び替えられる
javascript// 文字列の長さで並び替え
const words = ['JavaScript', 'HTML', 'CSS', 'TypeScript'];
const sortedByLength = sortBy(words, (word) => word.length);
console.log(sortedByLength); // ['CSS', 'HTML', 'JavaScript', 'TypeScript']
複数キーでの並び替え手法
sortBy の真の力は、複数の条件を組み合わせた並び替えにあります。
javascript// 複数条件での並び替え
const employees = [
{ name: '田中', department: '営業', salary: 400000 },
{ name: '佐藤', department: '開発', salary: 500000 },
{ name: '鈴木', department: '営業', salary: 450000 },
{ name: '高橋', department: '開発', salary: 480000 },
];
// 部署別、同部署内では給与順で並び替え
const sortedEmployees = sortBy(employees, [
'department',
'salary',
]);
console.log(sortedEmployees);
配列で複数の条件を指定することで、優先順位に従って並び替えが実行されます。最初の条件で同じ値の場合は、次の条件で比較されます。
javascript// 関数と文字列を組み合わせた複数条件
const sortedComplex = sortBy(employees, [
'department', // 部署名(昇順)
(employee) => -employee.salary, // 給与(降順)
]);
以下の図は、複数条件での並び替えの処理フローを示しています。
mermaidflowchart LR
data[元データ] --> sort1[第1条件で並び替え]
sort1 --> sort2[第2条件で並び替え]
sort2 --> sort3[第3条件で並び替え]
sort3 --> result[最終結果]
subgraph "安定ソート"
sort1
sort2
sort3
end
sortBy は安定ソートを使用するため、前の条件での順序が保持されながら次の条件が適用されます。
具体例
文字列・数値での基本並び替え
実際のプロジェクトでよく使われる基本的な並び替えパターンを見ていきましょう。
javascriptimport { sortBy } from 'lodash';
// 文字列配列の並び替え(日本語対応)
const prefectures = [
'東京都',
'大阪府',
'北海道',
'沖縄県',
'愛知県',
];
const sortedPrefectures = sortBy(prefectures);
console.log(sortedPrefectures);
// ['愛知県', '大阪府', '沖縄県', '北海道', '東京都']
javascript// 数値配列の並び替え
const scores = [85, 92, 78, 95, 88, 76];
const sortedScores = sortBy(scores);
console.log(sortedScores); // [76, 78, 85, 88, 92, 95]
// 降順で並び替えたい場合
const sortedScoresDesc = sortBy(scores, (score) => -score);
console.log(sortedScoresDesc); // [95, 92, 88, 85, 78, 76]
オブジェクト配列の並び替え
EC サイトの商品一覧のような、実際のビジネスロジックでよく見る例を実装してみましょう。
javascript// 商品データの例
const products = [
{
id: 1,
name: 'ワイヤレスヘッドホン',
price: 15800,
category: 'オーディオ',
rating: 4.5,
inStock: true,
},
{
id: 2,
name: 'Bluetooth スピーカー',
price: 8900,
category: 'オーディオ',
rating: 4.2,
inStock: false,
},
{
id: 3,
name: 'スマートウォッチ',
price: 25000,
category: 'ウェアラブル',
rating: 4.7,
inStock: true,
},
];
javascript// 価格の安い順で並び替え
const sortedByPrice = sortBy(products, 'price');
console.log(
'価格順:',
sortedByPrice.map((p) => `${p.name}: ¥${p.price}`)
);
javascript// 評価の高い順で並び替え
const sortedByRating = sortBy(
products,
(product) => -product.rating
);
console.log(
'評価順:',
sortedByRating.map((p) => `${p.name}: ${p.rating}★`)
);
javascript// 在庫あり商品を優先し、その中で価格の安い順
const sortedByStockAndPrice = sortBy(products, [
(product) => !product.inStock, // 在庫ありを優先(false が先に来る)
'price', // 価格の安い順
]);
console.log('在庫・価格順:', sortedByStockAndPrice);
複雑な条件での並び替え実装
より実践的な例として、従業員管理システムでの複雑な並び替えを実装してみます。
javascript// 従業員データの例
const employees = [
{
id: 1,
name: '田中太郎',
position: 'マネージャー',
department: '営業部',
hireDate: '2020-04-01',
salary: 550000,
performance: 'A',
},
{
id: 2,
name: '佐藤花子',
position: 'エンジニア',
department: '開発部',
hireDate: '2019-07-15',
salary: 480000,
performance: 'B',
},
{
id: 3,
name: '鈴木一郎',
position: 'エンジニア',
department: '開発部',
hireDate: '2021-01-10',
salary: 420000,
performance: 'A',
},
];
javascript// 部署別、同部署内では役職別、同役職では評価順で並び替え
const departmentOrder = { 開発部: 1, 営業部: 2, 総務部: 3 };
const positionOrder = {
マネージャー: 1,
リーダー: 2,
エンジニア: 3,
};
const performanceOrder = { A: 1, B: 2, C: 3 };
const complexSorted = sortBy(employees, [
(emp) => departmentOrder[emp.department] || 999,
(emp) => positionOrder[emp.position] || 999,
(emp) => performanceOrder[emp.performance] || 999,
]);
console.log('複合条件並び替え:', complexSorted);
javascript// 入社年数を計算して並び替え
const currentDate = new Date();
const sortedByExperience = sortBy(employees, (employee) => {
const hireDate = new Date(employee.hireDate);
const yearsDiff =
currentDate.getFullYear() - hireDate.getFullYear();
return -yearsDiff; // 経験年数の長い順(降順)
});
console.log('経験年数順:', sortedByExperience);
ネストしたプロパティでの並び替え
深い階層を持つオブジェクトの並び替えも、sortBy なら簡潔に記述できます。
javascript// ネストした構造のデータ例
const companies = [
{
name: 'テックカンパニーA',
location: {
country: '日本',
prefecture: '東京都',
city: '渋谷区',
},
financial: {
revenue: 50000000,
employees: 120,
},
},
{
name: 'スタートアップB',
location: {
country: '日本',
prefecture: '大阪府',
city: '大阪市',
},
financial: {
revenue: 12000000,
employees: 45,
},
},
];
javascript// ネストしたプロパティでの並び替え
const sortedByRevenue = sortBy(
companies,
'financial.revenue'
);
console.log('売上順:', sortedByRevenue);
// より複雑なネストプロパティの場合は関数を使用
const sortedByLocation = sortBy(companies, [
'location.prefecture',
(company) => company.financial.employees,
]);
console.log('地域・従業員数順:', sortedByLocation);
以下の図は、sortBy による多段階並び替えの概念を示しています。
mermaidsequenceDiagram
participant Client as クライアント
participant SortBy as sortBy関数
participant Data as データ配列
Client->>SortBy: sortBy(data, ['dept', 'salary'])
SortBy->>Data: 第1条件:部署名で並び替え
Data-->>SortBy: 部署別グループ化完了
SortBy->>Data: 第2条件:各部署内で給与順並び替え
Data-->>SortBy: 最終並び替え完了
SortBy-->>Client: 並び替え済み配列を返却
図で理解できる要点:
- 複数条件は順番に処理される
- 前の条件での順序は保持される
- ネストしたプロパティも直感的にアクセス可能
まとめ
sortBy の活用メリット
Lodash の sortBy を使用することで、以下のような大きなメリットが得られます。
コードの簡潔性と可読性の向上
従来の Array.sort() では複雑になりがちな多条件並び替えが、非常にシンプルな記述で実現できます。特に複数の条件を配列で指定できる機能は、コードの可読性を大幅に向上させます。
メンテナンス性の向上
並び替え条件の追加や変更が容易になり、チーム開発での保守性が向上します。新しい開発者でも直感的に理解できるコードが書けるため、引き継ぎやレビューの効率も上がります。
パフォーマンスの最適化
Lodash は内部で最適化されたアルゴリズムを使用しており、手動実装よりも高いパフォーマンスが期待できます。特に大量のデータを扱う場合、その差は顕著に現れます。
実際の開発での効果的な使い方
実践的な開発において sortBy を効果的に活用するためのポイントをまとめます。
TypeScript との組み合わせ
typescriptinterface Product {
name: string;
price: number;
category: string;
}
const products: Product[] = [...];
const sorted = sortBy(products, ['category', 'price']);
型安全性を保ちながら、sortBy の恩恵を受けることができます。
パフォーマンスを考慮した実装
大量データを扱う場合は、並び替え条件を事前に計算しておくことで、パフォーマンスを向上させられます。
javascript// 重い計算を事前に実行
const productsWithScore = products.map((product) => ({
...product,
score: calculateComplexScore(product), // 重い計算
}));
// 事前計算した値で並び替え
const sorted = sortBy(productsWithScore, 'score');
チーム開発での活用
sortBy を使用することで、チーム内でのコードの統一性が向上し、レビューや保守が効率化されます。特に、並び替えロジックが複雑になりがちなプロジェクトでは、その効果は絶大です。
Lodash の sortBy は、JavaScript での配列並び替えをより簡単で強力なものにしてくれる優秀なツールです。基本的な使い方から応用的なテクニックまでを習得することで、様々な並び替え要求に柔軟に対応できるようになります。
ぜひ実際のプロジェクトで活用して、よりクリーンで保守性の高いコードを書いてみてください。
関連リンク
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来