TypeScriptのreduceを使って配列をグループ分けしてみた(TypeScriptでGroupByする)
#TypeScript
#reduce
#GroupBy
やりたいこと
HighChartsでチャートを作る際、seriesに種類ごとに配列をまとめる必要があり、以下のような様々なtypeが存在する配列をtypeごとにグループ化するようにパースしたい。
[ { id: 1, timestamp: 1647877105000, type: "sampleA", value: 30 }, { id: 2, timestamp: 1647913105000, type: "sampleA", value: 40 }, { id: 3, timestamp: 1647959905000, type: "sampleA", value: 10 }, { id: 4, timestamp: 1647877105000, type: "sampleB", value: 10 }, { id: 5, timestamp: 1647913105000, type: "sampleB", value: 5 }, { id: 6, timestamp: 1647927505000, type: "sampleB", value: 20 } ]
を
[ { name: "sampleA", data: [ { x: 1647877105000, y: 30, type: "sampleA" }, { x: 1647913105000, y: 40, type: "sampleA" }, { x: 1647959905000, y: 10, type: "sampleA" } ] }, { name: "sampleB", data: [ { x: 1647877105000, y: 10, type: "sampleB" }, { x: 1647913105000, y: 5, type: "sampleB" }, { x: 1647927505000, y: 20, type: "sampleB" } ] } ]
のようにしたい。
実現方法
一度typeの種類をまとめた配列を作りループしてtypeごとにfilterすることを考えたけど、何度もループ処理が必要なため効率が悪そう
reduceというメソッドが良さそう https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
reduce使用例
const array1 = [1, 2, 3, 4]; // 0 + 1 + 2 + 3 + 4 const initialValue = 0; const sumWithInitial = array1.reduce( (previousValue, currentValue) => previousValue + currentValue, initialValue ); console.log(sumWithInitial); // expected output: 10
reduceの()内の第一引数(previousValue)は初期値or前回のreturn の結果が入る。
第二引数(currentValue)はループごとの値が入る。
また、initialValueの位置に初期値を設定する。
ユースケースとして、配列をループさせて1ループずつ返り値となる値に変更を加えたい時などに使える。 上記の例だとループごとに値をインクリメントしている。
実装したコード
interface Sample { id: number; timestamp: number; type: string; value: number; } interface ParsedSample { name: string; data: { x: number; y: number; type: string; }[]; } export const parseArray = (records: Sample[]) => { return records.reduce((acc, cur) => { const findSample = acc.find((e) => { return e.name === cur.type; }); const datum = { x: cur.timestamp, y: cur.value, type: cur.type }; if (!findSample) { const obj = { name: cur.type, data: [] }; obj.data.push(datum); acc.push(obj); } else { findSample.data.push(datum); } return acc; }, [] as ParsedSample[]); };
解説
ループ処理ごとに処理結果の配列(acc)にfindで検索をかけ、typeの存在を確認する。 存在しない場合は新規レコードを作成、存在する場合はレコードの中の配列にオブジェクトを追加することで処理をした。
所感
突き詰めればもっと良いコードはありそう
ひとまず1ループでグループ化する処理を書けた