目次
概要
実務における「ソート(並べ替え)」のほとんどは、単純な数値や文字列の配列ではなく、データベースから取得した「オブジェクトの配列(JSONデータ)」を対象とします。
本記事では、オブジェクト内の特定のプロパティ(IDや名前、日付など)を基準にして、配列全体の順序を並べ替える実装パターンを解説します。
仕様(入出力)
オブジェクト配列のソートロジック
sort メソッドの引数である比較関数 (a, b) の中で、比較したいプロパティ同士 を取り出して計算します。
| 比較対象 | コード例(昇順) | 解説 |
| 数値プロパティ | (a, b) => a.id - b.id | 引き算の結果(負・0・正)を利用します。 |
| 文字列プロパティ | (a, b) => a.name.localeCompare(b.name) | localeCompare メソッドで辞書順比較を行います。 |
- 入力: オブジェクトを含む配列
- 出力: 特定のキーで並べ替えられた配列(破壊的変更)
基本の使い方
ID(数値)でソートする場合
オブジェクト a と b から、比較したい id プロパティを取り出して引き算します。
const users = [
{ id: 3, name: 'Tree' },
{ id: 1, name: 'Forest' }
];
// IDの昇順(小さい順)
users.sort((a, b) => a.id - b.id);
console.log(users);
// [{ id: 1, name: 'Forest' }, { id: 3, name: 'Tree' }]
コード全文(HTML / JavaScript)
社員名簿データを「社員番号順(数値)」や「フリガナ順(文字列)」に並べ替える管理画面のデモです。
指定された名前(森、小林、中林など) を使用したデータセットで構築します。
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Employee Directory Sort</title>
<style>
.directory-container {
font-family: 'Hiragino Kaku Gothic ProN', sans-serif;
max-width: 600px;
margin: 20px auto;
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px;
background-color: #fcfcfc;
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
button {
padding: 10px 15px;
cursor: pointer;
border: 1px solid #007bff;
background-color: #fff;
color: #007bff;
border-radius: 4px;
font-weight: bold;
}
button:hover, button.active {
background-color: #007bff;
color: #fff;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
text-align: left;
padding: 10px;
border-bottom: 1px solid #ddd;
}
th { background-color: #f0f0f0; color: #333; }
.id-col { width: 80px; text-align: center; }
.kana-col { color: #666; font-size: 0.85em; }
</style>
</head>
<body>
<div class="directory-container">
<h3>社員名簿一覧</h3>
<div class="controls">
<button id="sort-id">社員番号順 (1, 2...)</button>
<button id="sort-kana">フリガナ順 (あいう...)</button>
<button id="sort-desc">社員番号 降順 (9, 8...)</button>
</div>
<table>
<thead>
<tr>
<th class="id-col">ID</th>
<th>氏名</th>
<th>フリガナ</th>
</tr>
</thead>
<tbody id="employee-list">
</tbody>
</table>
</div>
<script src="directory_sort.js"></script>
</body>
</html>
JavaScript
/**
* 社員名簿ソートスクリプト
* オブジェクト配列のソートロジック実装
*/
// 1. 社員データ(オブジェクトの配列)
const employees = [
{ id: 104, name: '中林', kana: 'ナカバヤシ' },
{ id: 101, name: '森', kana: 'モリ' },
{ id: 103, name: '小林', kana: 'コバヤシ' },
{ id: 108, name: '大木', kana: 'オオキ' },
{ id: 102, name: '小木', kana: 'オギ' },
{ id: 105, name: '大森', kana: 'オオモリ' }
];
// DOM要素
const tbody = document.getElementById('employee-list');
const btnSortId = document.getElementById('sort-id');
const btnSortKana = document.getElementById('sort-kana');
const btnSortDesc = document.getElementById('sort-desc');
/**
* テーブルを描画する関数
*/
const renderTable = () => {
tbody.innerHTML = '';
employees.forEach(emp => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td class="id-col">${emp.id}</td>
<td>${emp.name}</td>
<td class="kana-col">${emp.kana}</td>
`;
tbody.appendChild(tr);
});
};
/**
* IDで昇順ソート (数値比較)
*/
const sortById = () => {
employees.sort((a, b) => a.id - b.id);
updateActiveButton(btnSortId);
renderTable();
};
/**
* IDで降順ソート (数値比較)
*/
const sortByIdDesc = () => {
employees.sort((a, b) => b.id - a.id);
updateActiveButton(btnSortDesc);
renderTable();
};
/**
* フリガナで昇順ソート (文字列比較)
*/
const sortByKana = () => {
employees.sort((a, b) => {
// localeCompareを使用して日本語の辞書順比較を行う
return a.kana.localeCompare(b.kana, 'ja');
});
updateActiveButton(btnSortKana);
renderTable();
};
/**
* ボタンの見た目を更新するヘルパー関数
*/
const updateActiveButton = (activeBtn) => {
// 全ボタンのactiveクラスを削除
[btnSortId, btnSortKana, btnSortDesc].forEach(btn => btn.classList.remove('active'));
// 押されたボタンにactiveクラスを付与
activeBtn.classList.add('active');
};
// 初期表示
renderTable();
// イベントリスナー
btnSortId.addEventListener('click', sortById);
btnSortKana.addEventListener('click', sortByKana);
btnSortDesc.addEventListener('click', sortByIdDesc);
カスタムポイント
- 日本語(漢字)のソート:漢字の名前(例: 「森」と「林」)を直接ソートしようとすると、文字コード順になり、期待する「あいうえお順」にはなりません。必ずフリガナのプロパティ(
kana)を持たせて、それを基準にlocaleCompareすることをお勧めします。 - 日付のソート:
Dateオブジェクトを持つプロパティの場合は、a.date.getTime() - b.date.getTime()のように数値(タイムスタンプ)に変換してから引き算します。
注意点
- プロパティの存在保証比較するプロパティ(例:
a.kana)がundefinedやnullの場合、エラーになったり予期せぬ順序になったりします。データに欠損がある可能性がある場合は、空文字に置換するなどのガード処理が必要です。const valA = a.kana || ''; - 文字列と数値の混同IDが文字列の
"101"と数値の102で混在していると正しくソートできません。必ず型を統一するか、比較関数内でNumber(a.id)のように変換してください。
応用
複合ソート(多重ソート)
「部署コード順」に並べ、同じ部署の中では「役職順」に並べる、といった実装です。
employees.sort((a, b) => {
// 1. まず部署コードで比較
if (a.deptId !== b.deptId) {
return a.deptId - b.deptId;
}
// 2. 部署が同じなら、役職ランクで比較(数値が小さいほど偉いとする)
return a.rank - b.rank;
});
まとめ
オブジェクト配列のソートは、比較関数 (a, b) => ... の書き方次第で自由にコントロールできます。
- 数値なら
a.prop - b.prop - 文字列なら
a.prop.localeCompare(b.prop)
この2つのパターンを基本とし、必要に応じて複合条件を組み込むことで、あらゆる業務データの並べ替えに対応できます。
