2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScript:キーを複数指定したら集計してくれるgroupByを考えてみた

Last updated at Posted at 2020-03-09

(この記事は、ある記事のコメントに書いたものが元になっています。
なぜか元の記事が削除されてしまったので、せっかく考えたのにもったいないなあと思って投稿しました。何か問題のある内容でしたらお知らせください。)

ちゃんとやるには何かデータベース的なものが必要ですが、そこまででない、ちょっと集計して表示したい、とかのときに使えそうなものです。
いろいろ複雑な計算ができるようにするのは大変なので、とりあえず集計だけしてくれる関数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 }
]
*/

合計、平均、カウントなどの定型処理の便利な関数も作れそうですが、力尽きました。今日はここまで。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?