(この記事は、ある記事のコメントに書いたものが元になっています。
なぜか元の記事が削除されてしまったので、せっかく考えたのにもったいないなあと思って投稿しました。何か問題のある内容でしたらお知らせください。)
ちゃんとやるには何かデータベース的なものが必要ですが、そこまででない、ちょっと集計して表示したい、とかのときに使えそうなものです。
いろいろ複雑な計算ができるようにするのは大変なので、とりあえず集計だけしてくれる関数groupByを考えてみました。
const groupBy = (...keys) => xs =>
xs.reduce(updateGB(...keys), [])
const updateGB = (...keys) => (acc, e) => {
const foundI = acc.findIndex( d => keys.every( key => d[key] === e[key]))
const divided = divProps(...keys)(e)
return foundI === -1 ? [...acc, {...divided.labels, data:[divided.data]}]
: (acc[foundI].data = [...acc[foundI].data, divided.data], acc)
}
const divProps =(...keys) => e =>
Object.entries(e).reduce(
( acc, [k, v] ) =>
keys.includes(k)? {...acc, labels:{...acc.labels, [k]:v}}
: {...acc, data:{...acc.data, [k]:v}}
, {labels:{}, data:{}}
)
こんな風に使います。
const sampleArray = [
{ id: 1, a: 100, b: 110 },
{ id: 2, a: 600, b: 210 },
{ id: 1, a: 100, b: 310 },
{ id: 3, a: 400, b: 410 },
{ id: 2, a: 500, b: 510 },
{ id: 1, a: 100, b: 110 },
{ id: 2, a: 500, b: 210 },
]
// 集計する
groupBy("id","a")(sampleArray)
/*
[
{ id: 1, a: 100, data: [ [Object], [Object], [Object] ] },
{ id: 2, a: 600, data: [ [Object] ] },
{ id: 3, a: 400, data: [ [Object] ] },
{ id: 2, a: 500, data: [ [Object], [Object] ] }
]
*/
キーが同じオブジェクトのキー以外の部分(この場合は {b:foo}
) が、data以下にまとめられています。
あとはいいように加工して表示するだけです。
データを合計して、キーの降順に並べ替えてみました。
// 配列の要素のプロパティを合計する関数
const sumProp = prop => xs =>
xs.reduce( (acc, e) => acc + e[prop], 0)
// 集計したデータを加工して表示してみる。
console.log(
groupBy("id","a")(sampleArray)
.map(
e => ({
id:e.id
, a:e.a
, b:sumProp("b")(e.data)
})
)
.sort( (a, b) => a.id - b.id || a.a - b.a )
)
/*
[
{ id: 1, a: 100, b: 530 },
{ id: 2, a: 500, b: 720 },
{ id: 2, a: 600, b: 210 },
{ id: 3, a: 400, b: 410 }
]
*/
合計、平均、カウントなどの定型処理の便利な関数も作れそうですが、力尽きました。今日はここまで。