SixtyEight
SixtyEight

Reputation: 2480

How to remove any empty objects from array of nested objects

I've got a data array:

const data = [{
  name: 'South America',
  locations: [{
    name: 'Argentina',
    locations: [{
      name: 'Buenos Aires'
    }, {}]
  }]
}, {
  name: 'Europe',
  locations: [{
    name: 'Spain',
    locations: [{}]
  }]
}, {
  name: 'Asia',
  locations: [{}]
}]

I'd like to remove any empty objects on any level (even if it's really deep). Returning as the example below:

[{
  name: 'South America',
  locations: [{
    name: 'Argentina',
    locations: [{
      name: 'Buenos Aires'
    }]
  }]
}, {
  name: 'Europe',
  locations: [{
    name: 'Spain',
    locations: []
  }]
}, {
  name: 'Asia',
  locations: []
}]

The key locations could be anything else.

My solution is just partial as it only deletes the first level.

FAILED ATTEMPT

const result = data.filter(value => Object.keys(value).length !== 0)

I'd like this to be as dynamic as possible, without having to specify how nested will it be.

Upvotes: 1

Views: 804

Answers (2)

Nenad Vracar
Nenad Vracar

Reputation: 122037

You could use create a recursive function with reduce and a for...in loop and make it so that both empty objects in a array and as a object value are removed.

const data = [{"name":"South America","locations":[{"name":"Argentina","locations":[{"name":"Buenos Aires","foo":{}},{}]}]},{"name":"Europe","locations":[{"name":"Spain","locations":[{}]}]},{"name":"Asia","locations":[{}]}]

function removeEmpty(data) {
  return data.reduce((r, e) => {
    if (Object.keys(e).length) {
      const obj = {}

      for (let k in e) {
        if (Array.isArray(e[k])) {
          obj[k] = removeEmpty(e[k])
        } else if (typeof e[k] === 'object') {
          if (Object.keys(e[k]).length) {
            obj[k] = removeEmpty(e[k])
          }
        } else {
          obj[k] = e[k]
        }
      }

      r.push(obj)
    }

    return r;
  }, [])
}

console.log(removeEmpty(data))

Upvotes: 1

Alexander Lonberg
Alexander Lonberg

Reputation: 345

const data = [{
  name: 'South America',
  locations: [{
    name: 'Argentina',
    locations: [{
      name: 'Buenos Aires'
    }, {}]
  }]
}, {
  name: 'Europe',
  locations: [{
    name: 'Spain',
    locations: [{}]
  }]
}, {
  name: 'Asia',
  locations: [{}]
}]

const isArray = Array.isArray
const isObject = (any) => typeof any === 'object' && any !== null

function clear(obj) {
  (function recursive(any, remove) {
    if (isArray(any)) {
      for (let i = 0; i < any.length; ++i) {
        recursive(any[i], () => {
          any.splice(i--, 1)
        })
      }
    }
    else if (isObject(any)) {
      const values = Object.values(any)
      if (values.length) {
        for (let item of values) {
          recursive(item, () => null)
        }
      } else {
        remove() // <- delete {}
      }
    }
  })(obj, () => null)
}

// 
clear(data)
console.log(data)

Upvotes: 0

Related Questions