【JS】２次元のオブジェクトの要素と同じ次元に新たな要素を追加する方法。map & reduce & concat

#２次元のオブジェクトの要素と同じ次元に新たな要素を追加する方法

タイトルが長くてわかりにくいが、以下のようなことを実現する方法について。

２次元のオブジェクトの要素に新たなオブジェクトを追加したり、元のオブジェクトの値を変更したり、プロパティの追加を行う。

`[{c:[{d:9, e:8}]}]`　　
　　↓
`[{c:[{x:100}, {d:200, e:8, f:7}]}]`


map & reduce & concatメソッドを使うことで実現できる。


<br>
**▼実現したいこと**

最終的には、条件分岐によって、指定した２次元のオブジェクトに新たにプロパティを追加したり、変更したりする。

```:元のオブジェクト
[{a:1, b:2, c:[{d:9, e:8}, {d:9, e:8}]}, {a:3, b:4, c:[{d:7, e:6}]}]
```

↓

```:出力結果
[{a:1, b:2, c:[{d:100, e:8}, {x:100}, {d:9, e:8}],}, {a:3, b:4, c:[{y:200}, {d:7, e:6, f:5}]}]
```

**▼やっていること**

- 0番目の要素
    - プロパティcの0番目のdの値を100に変更。
    - 真ん中に {x:100}　を追加。
- 番目の要素
    - 前方に {y:200}　を追加。
    - プロパティd, eと同じ次元に f:5 を追加。



<br>
##新たな要素を追加する方法

２次元のオブジェクトに新たな要素を追加する方法は以下のようになる。

`[{c:[{d:9, e:8}]}]`　　
　　↓
`[{c:[{x:100}, {d:9, e:8}]}]`

```js:
objs = [{c:[{d:9, e:8}]}]

res = objs.map( (obj, index) => {
    elem = obj.c.map( (x, xIndex) => {
        return [
            {x:100},
            x
        ]
    })
    .reduce( (arrs, arr) => 
        arr.concat(arrs)
    , [] ) 

    return {
        ...obj,
        c: elem
    }
})

console.log(res) //[{c:[{x:100}, {d:9, e:8}]}]
```

●`objs.map( (obj, index) => {return 処理}`
１回目のmapで、`{c:[{d:9, e:8}]}`をobjとして抜き出して処理する。

インデックス番号が入った変数indexはここでは使っていないので記述しなくてもいい。（後の条件分岐で使用する）


<br>
●`obj.c.map( (x, xInex) => { return 処理}`
２回目のmapで、{d:9, e:8}をxとして取り出して処理する。
xIndexも前述のindexと同じ。

ポイントは処理結果を、配列に格納している点。
`[{x:100}, x]`が処理結果として返る。


<br>
●`.reduce( (arrs, arr) =>　処理, 初期値 )`
obj.c.mapの処理結果をreduce & concatで１次元下げている。`{x:100}, x`が返る。

<br>
●`return { ...obj, c:elem}`
一番最初のobjs.mapの処理結果として、obj内のプロパティcの値をelemに置き換えた値を返す。

```js:
obj = {c:[{d:9, e:8}]}
elem = {x:100}, x
x = {d:9, e:8}
```

よって、`{c:[{x:100}, {d:9, e:8}]}` が返る。

最終的なアウトプットは`[{c:[{x:100}, {d:9, e:8}]}]`となる。

>[reduce & concatの詳細](https://qiita.com/yuta-38/items/7552b36d24db3f2d0b94)



<br>
##プロパティの変更と追加
次に、プロパティの値を変更したり、新たなプロパティを追加する方法について。

`[{c:[{d:9, e:8}]}]`　　
　　↓
`[{c:[{d:200, e:8, f:7}]}]`


```js:
objs = [{c:[{d:9, e:8}]}]

res = objs.map( (obj, index) => {
    elem = obj.c.map( (x, xIndex) => {
      return {
          ...x,
          d: 200,
          f: 7
      }
    })

    return {
        ...obj,
        c: elem
    }
})

console.log(res) //[{c:[{d:200, e:8, f:7}]}]
```

●`objs.map( (obj, index) => {return 処理}`
１回目のmapで、`{c:[{d:9, e:8}]}`をobjとして抜き出して処理する。

インデックス番号が入った変数indexはここでは使っていないので記述しなくてもいい。（後の条件分岐で使用する）


<br>
●`obj.c.map( (x, xInex) => { return 処理}`
２回目のmapで、{d:9, e:8}をxとして取り出して処理する。
xIndexも前述のindexと同じ。

ポイントはxをスプレッド構文で開き、dの値を200に、f: 7を追加している点。

先ほどは、returnで配列を返したが、今回はオブジェクトを返している。

 <br>
●`return { ...obj, c:elem}`
一番最初のobjs.mapの処理結果として、obj内のプロパティcの値をelemに置き換えた値を返す。

```js:
obj = {c:[{d:9, e:8}]}
x = {d:9, e:8}
elem = {d:200, e:8, f:7}
```

よって、`{c:[{d:200, e:8, f:7}]}` が返る。

最終的なアウトプットは`[{c:[{d:200, e:8, f:7}]}]`となる。


>[２次元オブジェクトのプロパティ変更と追加の詳細](https://qiita.com/yuta-38/items/692cebf2988410a67951)



<br>
##要素の追加とプロパティの変更と追加
上記２つの処理を組み合わせる。

`[{c:[{d:9, e:8}]}]`　　
　　↓
`[{c:[{x:100}, {d:200, e:8, f:7}]}]`

```js:
objs = [{c:[{d:9, e:8}]}]

res = objs.map( (obj, index) => {
    elem = obj.c.map( (x, xIndex) => {
      return [
          {x: 100},
          {
          ...x,
          d: 200,
          f: 7
          }
      ]
    }).reduce( (lists, list) => {
        lists.concat(list)
    , []})

    return {
        ...obj,
        c: elem
    }
})

console.log(res) //[{c:[{x:100}, {d:200, e:8, f:7}]}]
```


obj.c.mapの戻り値を配列、
`return [{x: 100}, {...x, d: 200, f: 7}]`
で返し、reduce & concatで次元を下げる。



<br>
##条件分岐
要素が複数ある場合に条件分岐によって処理を返る場合を考える。

```:元のオブジェクト
[{a:1, b:2, c:[{d:9, e:8}, {d:9, e:8}]}, {a:3, b:4, c:[{d:7, e:6}]}]
```

↓

```:出力結果
[{a:1, b:2, c:[{d:100, e:8}, {x:100}, {d:9, e:8}],}, {a:3, b:4, c:[{y:200}, {d:7, e:6, f:5}]}]
```



<br>
**▼コード**

```js:
objs = [{a:1, b:2, c:[{d:9, e:8}, {d:9, e:8}]}, {a:3, b:4, c:[{d:7, e:6}]}]

res = objs.map( (obj, index) => {
    elem = obj.c.map( (x, xIndex) => {
      if( index == 0 && xIndex == 0 ){
          return [
              {
                  ...x,
                  d: 100,
              },
              {x: 100}
          ]
      }else if( index == 1 ){
          return [
            {y: 200},
            {
                ...x,
                f: 5
            }
          ]
      } else { return [x] }
    }).reduce( (lists, list) => 
        lists.concat(list)
    , [])


    return {
        ...obj,
        c: elem
    }
})

console.log(res) //[{a:1, b:2, c:[{d:100, e:8}, {x:100}, {d:9, e:8}],}, {a:3, b:4, c:[{y:200}, {d:7, e:6, f:5}]}]
```

以上。

一気に見るとややこしいが、分解して組み合わせると理解しやすい。