SleBluue
SleBluue

Reputation: 277

Javascript - Flatten nested arrays of objects. Make it pretty?

I am working on formatting a set of data into one array to use for a table. I have a data set like this

data = [{
  hello: 'world',
  children: [{
    foo: 'bar'
  }]
}]

I am looking to get this data into one array while marking all of the parent nodes with a parent: true bool. So I can throw it all into a table but still have a differentiating factor between a parent and child. I know I can just loop twice for the table but I am doing this for reusability purposes. I have a working block of code below.

  formattedData (data) {
    const formattedData = []
    data.map(dataPoint => {
      let obj = dataPoint
      obj['parent'] = true
      formattedData.push(dataPoint)
      if (dataPoint.children) {
        dataPoint.children.map(c => {
          formattedData.push(c)
        })
      }
    })
    return formattedData
  }

Resulting data looks like this:

data = [{
  hello: 'world', 
  parent: true
}, {
  foo: 'bar'
}]

Just checking to see if there is a better/more efficient/prettier way to do this (or if the way I did it is how it should be done). Thanks in advance!

Upvotes: 0

Views: 148

Answers (2)

Akrion
Akrion

Reputation: 18525

You could do this with a single Array.reduce, Object.assign and some ES6 destructuring:

const data = [{ hello: 'world', children: [{ foo: 'bar' }], }, { hello: 'world2' }]

const result =  data.reduce((r, {children, ...other}) => {
  if(children){
    r.push(Object.assign({}, other, {parent: true}))
    r.push(...children)		
  } else r.push(Object.assign({}, other))
  return r	
}, [])

console.log(result)

If however you have further children levels then you would have to use a recursive approach but based on the input data that does not seem to be the case.

You can also shorten if further if you are not concerned about readability:

const data = [{ hello: 'world', children: [{ foo: 'bar' }], }, { hello: 'world2' }]

const result =  data.reduce((r, {children, ...other}) => {
  r.push(Object.assign({}, other, children ? {parent: true} : {}))
  children ? r.push(...children) : null
  return r	
}, [])

console.log(result)

Upvotes: 1

Ry-
Ry-

Reputation: 225105

  • If you meant to copy the object with let obj = dataPoint to not mutate the argument passed to the function and the object is a simple Object, you can use object spread to copy it and add a property

  • Array.prototype.flatMap exists now (and can be made backwards-compatible with shims like everything else)

  • Why is it a class method if it doesn’t use this?

const getFormattedData = data =>
  data.flatMap(dataPoint => [
    {...dataPoint, parent: true},
    ...dataPoint.children || [],
  ])

Or, if you also wanted to remove the children property:

const getFormattedData = data =>
  data.flatMap(({children, ...dataPoint}) => [
    {...dataPoint, parent: true},
    ...children || [],
  ])

Upvotes: 2

Related Questions