分類してまとめる groupBy
このレッスンで分かること
- 分類は
reduceの初期値を空オブジェクトにすると書けます- そのキーが無い最初の 1 件だけ、入れ物を用意する必要があります
分類の数だけ filter を呼びたくない
年ごとの見出しを作りたいとき、filter を年の数だけ並べる書き方が真っ先に浮かびます。動きはしますが、年が増えるたびに行が増え、データを何周もします。何より、どんな年があるかを先に知っていないと書けません。
やりたいのは「キーごとのまとまりを持つ 1 つのオブジェクトを作る」ことです。配列から 1 つの値を作るので、担当は reduce です。学習メモを月ごとにまとめる例で見ます。
JavaScript
const notes = [
{ month: "2026-05", topic: "Flexbox" },
{ month: "2026-05", topic: "Grid" },
{ month: "2026-06", topic: "fetch" }
];
const byMonth = notes.reduce((acc, note) => {
const key = note.month;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(note.topic);
return acc;
}, {});
// { "2026-05": ["Flexbox", "Grid"], "2026-06": ["fetch"] }大事なのは真ん中の 3 行です。そのキーがまだ無いときだけ、空の配列を用意します。これを書かないと、初回の push が undefined に対して呼ばれて落ちます。
存在の確認を
acc[key]の真偽値で済ませられるのは、値が配列だからです。あるときは必ず truthy になります。値が0や空文字になり得る集計では、この判定は使えません。
件数だけなら 3 行が 1 行になる
配列ではなく件数だけほしいなら、値を数値にします。無いときは 0 から始める、と書ければ入れ物の用意が消えます。
JavaScript
const counts = notes.reduce((acc, note) => {
acc[note.month] = (acc[note.month] || 0) + 1;
return acc;
}, {});
// { "2026-05": 2, "2026-06": 1 }分類の軸を変えたいときは、キーを決める式を差し替えるだけです。値の足しかたを変えれば、件数の代わりに合計も最大も出せます。分類は「キーを決める式」と「値の足しかた」の 2 か所でできている、と覚えておくと応用が効きます。
ひとつ注意が要るのは、タグのように 1 件が複数の分類に入る軸です。この場合はキーが 1 つに決まらないので内側でもう 1 周することになり、キーごとの件数を足しても元の件数には戻りません。合計が合わないと思ったら、まずこの形になっていないかを疑います。
キーは必ず文字列になる
オブジェクトのキーは文字列です。数値を書いても、内部では文字列に直されます。
JavaScript
const acc = {};
acc[2026] = 1;
console.log(acc["2026"]); // 1
console.log(Object.keys(acc)); // ["2026"]意図せず数値のまま扱うと、あとで比較したときに型が合わずに困ります。キーを作る時点で String で包んでおくと、読む人にも「ここは文字列だ」と伝わります。キーになる値が未設定のときは "undefined" という文字列のキーができてしまうので、軸に使う項目は値があるかを先に確かめるか、無いときの受け皿になるキーをこちらで決めておきます。
数値のキーを持つオブジェクトは、Object.keys で取り出したときに昇順へ並べ替えられます。新しい順に見せたいなら、並び順はキーに頼らず、取り出したあとで自分で並べ替えます。
よくある間違い
- キーが無いときの初期化を忘れる —
acc[key].push(...)を単独で書くと、そのキーの初回で必ず落ちます - コールバックで
accを返し忘れる —pushは追加したあとの長さを返すので、(acc, x) => acc[key].push(x)と書くと次の回のaccが数値になります。最後にaccを返してください - 0 件のときの戻り値を勘違いする — 初期値が空オブジェクトなので、返るのは空オブジェクトであって
nullでもundefinedでもありません。0 件かどうかはObject.keysの長さで分かります
要件
- 関数名は groupWorksByYear とし、引数は作品の配列 works を 1 つだけ受け取る
- 戻り値はオブジェクトで、キーは year を文字列にしたもの、値はその年の title を並べた配列にする
- published は条件に使わず、すべての作品を分類に含める
- 同じ年の作品は元の配列に出てきた順に並べ、空配列を渡されたときは空オブジェクトを返す