omygoodness
omygoodness

Reputation: 365

Ramda - how to groupBy and transform

I am trying to group elements by groupId and create a new structure.

Elements to group (For presentation purposes each group contains only one element but there are multiple groups with multiple elements):

const nodes = [
    {
        "id": 163779,
        "groupId": 0,
        "width": 400,
        "height": 368.28125
    },
    {
        "id": 163783,
        "groupId": 1,
        "width": 216.40625,
        "height": 102.453125
    }
]

I tried to use R.groupBy(R.prop('groupId'))(nodes) and that worked fine as a first step as a result I got:

{
    "0": [
        {
            groupId: 0,
            height: 368.28125,
            id: 163779,
            width: 400
        }
    ],
    "1": [
        {
            groupId: 1,
            height: 102.453125,
            id: 163783,
            width: 216.40625
        }
    ]
}

But I don't know how to achieve such a structure:

[
  {
    "id": 0,
    "children": [
      {
        "id": 163779,
        "groupId": 0,
        "height": 368.28125,
        "width": 400
      }
    ]
  },
  {
    "id": 1,
    "children": [
      {
        "id": 163783,
        "groupId": 1,
        "height": 102.453125,
        "width": 216.40625
      }
    ]
  }
]

Any help would be appreciated. Thank you

Upvotes: 1

Views: 1145

Answers (1)

Ori Drori
Ori Drori

Reputation: 191986

Create a function using R.pipe. First group by the groupId, and then convert to an array of [key, value] pairs using R.toPairs. Map the array of pairs to the required form with R.zipObj.

const { pipe, groupBy, prop, toPairs, map, zipObj, nth } = R

const fn = pipe(
  groupBy(prop('groupId')), // group by groupId
  toPairs, // convert to an array of [key, value] pairs
  map(zipObj(['id', 'children'])), // map to the required form
)

const nodes = [{"id":163779,"groupId":0,"width":400,"height":368.28125},{"id":163783,"groupId":1,"width":216.40625,"height":102.453125}]

const result = fn(nodes)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

since R.groupBy converts the array to an object with groupId as the key, the groupId is convert to a string. You can add another step to convert it back to a number by mapping and evolving id to a number:

const { pipe, groupBy, prop, toPairs, map, zipObj, nth, evolve } = R

const fn = pipe(
  groupBy(prop('groupId')), // group by groupId
  toPairs, // convert to an array of [key, value] pairs
  map(zipObj(['id', 'children'])), // map to the required form
  map(evolve({ id: Number })) // convert the id to number if needed
)

const nodes = [{"id":163779,"groupId":0,"width":400,"height":368.28125},{"id":163783,"groupId":1,"width":216.40625,"height":102.453125}]

const result = fn(nodes)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Upvotes: 3

Related Questions