🐡
[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.