🐡
[JavaScript]配列に格納されているオブジェクトをグルーピング
何番煎じかと思いますが、実装の機会があったのでまとめておきます。
やりたいこと
配列に格納されているオブジェクトを
[
{ fruit_id: 1, option_name: 'バナナ' },
{ fruit_id: 1, option_name: 'バナナ' },
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 3, option_name: 'ぶどう' },
{ fruit_id: 3, option_name: 'ぶどう' }
]
fruit_id ごとに配列でまとめます。
[
[
{ fruit_id: 1, option_name: 'バナナ' },
{ fruit_id: 1, option_name: 'バナナ' }
],
[
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' }
],
[
{ fruit_id: 3, option_name: 'ぶどう' },
{ fruit_id: 3, option_name: 'ぶどう' }
]
]
方針
Mapを利用します。
fruit_id を key にして value に fruit_id ごとの配列を格納していきます。
実装
const fruits = [
{
fruit_id: 1,
option_name: "バナナ"
},
{
fruit_id: 1,
option_name: "バナナ"
},
{
fruit_id: 2,
option_name: "りんご"
},
{
fruit_id: 2,
option_name: "りんご"
},
{
fruit_id: 2,
option_name: "りんご"
},
{
fruit_id: 3,
option_name: "ぶどう"
},
{
fruit_id: 3,
option_name: "ぶどう"
}
]
const formatedFruits = [];
const nMap = new Map();
for (let i = 0; i < fruits.length; i++) {
const fruit = fruits[i]
if (nMap.get(fruit.fruit_id)) {
const tempArray = nMap.get(fruit.fruit_id);
tempArray.push(fruit);
nMap.set(fruit.fruit_id, tempArray);
} else {
nMap.set(fruit.fruit_id, [fruit]);
}
}
for (const fruitsPerFruitID of nMap.values()) {
formatedFruits.push(fruitsPerFruitID)
}
解説
空の配列と Map インスタンスを生成します。
const formatedFruits = [];
const nMap = new Map();
for文でループして fruit を抽出します。
Map の get メソッドを使用して key に値が格納されているか確認します。
const fruit = fruits[i]
// key に値があるか確認
if (nMap.get(fruit.fruit_id)) {
値がある = 配列が格納されている想定のため、配列の値を取得します。
配列の push メソッドを使用して fruit を格納します。
Map の set メソッドで fruit_id を key にした新たな配列をセットします。
const tempArray = nMap.get(fruit.fruit_id);
tempArray.push(fruit);
nMap.set(fruit.fruit_id, tempArray);
それ以外の場合はまだ key に値がないということなので、配列としてセットします。
} else {
nMap.set(fruit.fruit_id, [fruit]);
}
以上を繰り返すとこのような値になります。
console.log(nMap)
Map(3) {
1 => [
{ fruit_id: 1, option_name: 'バナナ' },
{ fruit_id: 1, option_name: 'バナナ' }
],
2 => [
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' },
{ fruit_id: 2, option_name: 'りんご' }
],
3 => [
{ fruit_id: 3, option_name: 'ぶどう' },
{ fruit_id: 3, option_name: 'ぶどう' }
]
}
これを values メソッドを使用して Map 内の value を出力し、用意しておいた配列にガシガシ入れます。
for (const fruitsPerFruitID of nMap.values()) {
formatedFruits.push(fruitsPerFruitID)
}
以上です。
いろんなやり方あると思います。よかったら皆さんのやり方教えてください。
Discussion
以前、group関数を作ったことがあります。
配列の重複するオブジェクトを取り除きつつ数える unique関数 group 関数 の実装 - Qiita
どの項目でグループ化するのかを外部関数で指定できるようにしています。
tidyjsでやってみました
定義側
使用側
demo code.