はじめに
TypeScriptでオブジェクトの主キーを利用して同じものをまとめたいという質問を受けてアルゴリズムを書いたのでまとめておきます
問題
以下のデータがあるとします
type Person = {
name: string;
code: string;
memberId: string;
};
const people: Person[] = [
{ name: "John", code: "python", memberId: "1" },
{ name: "Jane", code: "java", memberId: "2" },
{ name: "Bob", code: "python", memberId: "3" },
{ name: "Alice", code: "javascript", memberId: "4" }
];
ここで、codeが同じものを集めて以下のような構造を作ります
{
python: [
{ name: "John", code: "python", memberId: "1" },
{ name: "Bob", code: "python", memberId: "3" }
],
java: [
{ name: "Jane", code: "java", memberId: "2" }
],
javascript: [
{ name: "Alice", code: "javascript", memberId: "4"}
]
}
解決方法
以下のような関数を作ってみました
export const groupBy = <T>(
list: T[],
getKey: (item: T) => PropertyKey,
): Record<PropertyKey, Record<PropertyKey, T[]>> => {
return list.reduce((acc, cur) => {
const key = getFirstKey(cur);
if (!acc[key]) acc[key] = {};
acc[key].push(cur);
return acc;
}, {} as Record<PropertyKey, Record<PropertyKey, T[]>>);
};
const groupBy = groupBy(people, person => person.code);
2つのキーを使ってまとめる
2つのキーでまとめる方法も考えました
export const groupBy = <T>(
list: T[],
getFirstKey: (item: T) => PropertyKey,
getSecondKey: (item: T) => PropertyKey
): Record<PropertyKey, Record<PropertyKey, T[]>> => {
return list.reduce((acc, cur) => {
const firstKey = getFirstKey(cur);
const secondKey = getSecondKey(cur);
if (!acc[firstKey]) acc[firstKey] = {};
if (!acc[firstKey][secondKey]) acc[firstKey][secondKey] = [];
acc[firstKey][secondKey].push(cur);
return acc;
}, {} as Record<PropertyKey, Record<PropertyKey, T[]>>);
};
type Person = {
name: string;
code: string;
memberId: string;
};
const people: Person[] = [
{ name: "John", code: "python", memberId: "1" },
{ name: "Jane", code: "java", memberId: "2" },
{ name: "Bob", code: "python", memberId: "3" },
{ name: "Alice", code: "javascript", memberId: "4" }
];
const grouped = groupBy(
people,
(person) => person.code,
(person) => person.memberId
);
console.log(grouped);
おわりに
この方法がわかるとフロントで表示するのが楽になりそうですね