
es-toolkit のMap用countBy完全ガイド変換関数によるエントリ集計の仕組みと実装【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkites-toolkitは、lodashに代わるモダンな JavaScript ユーティリティライブラリです。countByは、Mapの各エントリを変換関数で分類し、カテゴリごとの出現回数を数えるための関数で、es-toolkit/mapサブパスから利用できます。本記事では、公式リファレンスdocs/ja/reference/map/countBy.mdの内容を軸に、実際のソースコードとテストケースを照らし合わせながら、引数・戻り値・実装の内部動作・配列版・lodash 互換版との違いまでを体系的に解説します。概要と基本的な使い方countByは、Mapの各エントリに対してマッパー関数を適用し、生成されたキーごとの出現回数を集計して新しいMapとして返します。const counts countBy(map, mapper);エントリが「どのカテゴリにいくつ属しているか」を知りたいときに利用します。例えば、値の等しいエントリがいくつあるか、特定のプロパティごとに何件あるか、といった集計を 1 行で実現できます。import { countBy } from es-toolkit/map; const map new Map([ [a, 1], [b, 2], [c, 1], ]); const result countBy(map, value value); // 結果: Map(2) { 1 2, 2 1 }::: infoこの関数は、他のコレクション型向けの同名関数配列版countByなどとの潜在的な競合を避けるため、es-toolkit/mapからのみ利用できます。es-toolkit/mapは package.json のexports定義で公開されているサブパスです。:::様々な基準での集計パターンマッパー関数の書き方次第で、集計の基準を自由に設計できます。公式リファレンスが示す 3 パターンを確認しましょう。値のプロパティでカウントimport { countBy } from es-toolkit/map; const users new Map([ [user1, { name: Alice, age: 25, department: Engineering }], [user2, { name: Bob, age: 30, department: Engineering }], [user3, { name: Charlie, age: 35, department: Sales }], ]); const byDepartment countBy(users, user user.department); // 結果: Map(2) { Engineering 2, Sales 1 }派生値でカウントconst ages new Map([ [p1, 25], [p2, 30], [p3, 25], [p4, 40], ]); const ageGroups countBy(ages, age (age 30 ? young : senior)); // 結果: Map(2) { young 2, senior 2 }値とキーの両方を使用してカウントconst items new Map([ [alice, 20], [bob, 30], [carol, 20], ]); const firstLetter countBy(items, (value, key) key[0]); // 結果: Map(3) { a 1, b 1, c 1 }マッパー関数は(value, key, map)の 3 引数を受け取るため、値だけ・キーだけ・両方の組み合わせ、あるいは Map 全体の状態map.sizeなども参照して集計キーを決定できます。シグネチャと型定義パラメータパラメータ型説明mapMapK, V出現回数をカウントする対象の Mapmapper(value: V, key: K, object: MapK, V) K2カウント用のキーを生成する関数戻り値MapK2, number— マッピングされたキーとその個数を持つ新しい Map を返します。実際の宣言は src/map/countBy.ts で確認できます。export function countByK, V, K2 extends PropertyKey( map: MapK, V, mapper: (value: V, key: K, object: MapK, V) K2 ): MapK2, number型パラメータK2はPropertyKeystring | number | symbolに制約されており、マッパーが返すキーは JavaScript のオブジェクトキーとして扱える値であることが型レベルで保証されます。つまり、Symbolを集計キーとして使うことも可能ですこの点は後述のテストケースで検証されています。実装の内部動作src/map/countBy.ts の実装本体は非常にコンパクトです。export function countByK, V, K2 extends PropertyKey( map: MapK, V, mapper: (value: V, key: K, object: MapK, V) K2 ): MapK2, number { const result new MapK2, number(); for (const [key, value] of map) { const mappedKey mapper(value, key, map); result.set(mappedKey, (result.get(mappedKey) ?? 0) 1); } return result; }処理の流れは以下の 3 ステップです。空のMapK2, numberを用意します。入力Mapをfor...ofでイテレーションし、各エントリのvalueとkeyおよび元のmapをマッパーに渡して集計キーmappedKeyを生成します。result.get(mappedKey) ?? 0で既存カウントなければ 0を取り出し、1 した値をresult.setで書き戻します。ポイントは以下の通りです。集計は新規のMapに対して行われるため、入力のMapは一切変更されません純粋関数として動作。?? 0による初期化により、初回出現のキーも 1 からカウントが始まります。Mapを返すことで、Objectを戻り値とする配列版とは異なり、キーが__proto__やconstructorのようなプロパティ名と衝突する心配がありません。これは Map を使う最大の利点の一つです。また、src/map/index.tsでexport { countBy } from ./countBy.ts;として再エクスポートされており、es-toolkit/mapからのインポートが可能になっています。テストケースで確認する境界動作src/map/countBy.spec.ts には 12 個のテストケースが用意されており、公式リファレンスでは明示されていない境界動作を確認できます。テスト検証内容値ベースのカウント[a, 1], [b, 2], [c, 1]→Map { 1 2, 2 1 }キー変換ベースkey[0]でMap { a 1, b 1, c 1 }第 3 引数の Map 参照コールバックに渡されるobjectが元の Map と同一参照であることtoBe(map)空の Map空のMapを返す単一エントリMap { 42 1 }を返す元の Map を変更しない集計後も入力のエントリが変化しないこと同一キーへの全件集計全件が同じキーに集約されresult.size 1になること数値キーの Map[1, apple], [2, banana], [3, apricot]から先頭文字で集計オブジェクト値value.typeでfruit/vegetableに分類Symbol キーマッパーが返すSymbolをそのままキーとして集計できる剰余による分類偶数 / 奇数で{ odd: 3, even: 2 }特に「元の Map を変更しない」というテストは、Array.from(map.entries())でスナップショットを取り、集計前後で完全一致することを検証しています。副作用がない関数としての契約がテストで保証されている点は、実務で安心して使える根拠になります。配列版・lodash 互換版との違いcountByという名前の関数は es-toolkit 内に複数存在します。混乱を避けるために整理しておきます。配列版es-toolkit/es-toolkit/arraysrc/array/countBy.ts は配列を対象とし、戻り値がRecordK, numberプレーンなオブジェクトである点が Map 版と異なります。export function countByT, K extends PropertyKey( arr: readonly T[], mapper: (item: T, index: number, array: readonly T[]) K ): RecordK, number { const result {} as RecordK, number; for (let i 0; i arr.length; i) { const item arr[i]; const key mapper(item, i, arr); result[key] (result[key] ?? 0) 1; } return result; }配列版はインデックスiを第 2 引数に取る一方、Map 版はキーkeyを取る点も使い分けのポイントです。lodash 互換版es-toolkit/compatsrc/compat/array/countBy.ts は lodash のcountByと同じシグネチャ・戻り値Recordstring, numberを再現した互換実装です。ArrayLikeやnull/undefinedを受け入れ、iterateeにはショートハンドlengthのようなプロパティ名やオブジェクト、関数も渡せます。集計にはnull プロトタイプオブジェクトObject.create(null)を使い、constructorや__proto__のようなキーが他のキーと同様に安全に扱えるよう配慮し、最後に通常のオブジェクトへプロトタイプを戻しています。用途に応じて以下のように使い分けるのが自然です。型安全かつ Symbol キーも扱いたい場合→es-toolkit/mapのcountBy本記事の主対象配列を集計したい場合→es-toolkit/es-toolkit/arrayのcountBylodash からの移行時に既存コードをそのまま動かしたい場合→es-toolkit/compatのcountBy関連関数との組み合わせcountByとよく似た位置づけの関数として、同じes-toolkit/mapモジュールにkeyByがありますsrc/map/keyBy.ts。keyByはマッパーが生成したキーごとに「値」を保持するのに対し、countByは「個数」を集計する点が決定的な違いです。複数エントリが同一キーにマップされた場合、keyByは最後に出現した値を採用し、countByはカウントを加算していきます。「グループごとの代表値を取りたい」ならkeyBy、「グループごとの件数を出したい」ならcountByと、目的に応じて選択しましょう。まとめes-toolkit/mapのcountByは、Mapのエントリを変換関数で分類して出現回数を集計する、シンプルながら応用範囲の広い関数です。実装は 8 行にも満たない小さな関数ですが、for...ofによる単純な走査とMapによる集計、?? 0による初期化という基本構造に、型安全なPropertyKey制約と副作用ゼロの純粋性が組み合わされています。公式リファレンスdocs/ja/reference/map/countBy.mdの例と、テストケース で保証された境界動作を理解すれば、データ集計ロジックを安全かつ簡潔に実装できるようになるでしょう。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考