简体   繁体   中英

Recursively flatten a deeply-nested mix of objects and arrays

I'm trying to flatten a data object that contains mixed content (JavaScript within a React application). I just need the keys of every parent and child in the object; I don't necessarily need the values (though having them present wouldn't be a deal-breaker).

I've searched for over a week to find a solution that would fit my use case, but everything I've tried has fallen short, including vanilla JavaScript, Lodash, Underscore, and flat (NPM package).

In every case, I either get a shorter list than I expect (because I'm only getting the parents), or I get a fully-flattened object with dot notation-delimited objects, which is useless to me.

I know there are lots of questions & answers pertaining to this topic, but nothing I've seen matches my use case, and I can't seem to wrap my head around the problem.

Here is a sample of my data structure:

const sampleData = {
  coyotes: '',
  armadillos: false,
  wombats: [''],
  geckos: 0,
  dogs: {
    beagle: '',
    bulldog: ''
  },
  wolves: [
    {
      type: '',
      color: '',
      range: '',
      status: {
        endangered: true,
        protected: false
      }
    }
  ],
  cats: {}
}

Here is what I (ideally) want back:

result = {coyotes, armadillos, wombats, geckos, dogs, beagle, bulldog, wolves, type, color, range, status, endangered, protected, cats}

Here is the way I'd like to call the flattening method:

flattenData(sampleData)

Here's what I have so far:

const flattenData = (obj) =>
      Object.assign(
        {},
        ...(function _flatten (o) {
          return [].concat(...Object.keys(o)
            .map(k =>
              typeof o[k] === 'object' ? _flatten(o[k]) : (Number([k]) !== 0 && { [k]: o[k] })
            )
          )
        }(obj))
      )

...which produces:

{
    "coyotes": "",
    "armadillos": false,
    "geckos": 0,
    "beagle": "",
    "bulldog": "",
    "type": "",
    "color": "",
    "range": "",
    "endangered": true,
    "protected": false
}

As you'll note, some parents are missing (wombats, dogs, wolves and status), and an empty object is missing (cats).

This isn't the prettiest code I've ever wrote. Unfortunately it does get everything

const flattenData = (data) => {
  let results = [];
  const recursive = (data) => {
    Object.keys(data)
      .map(function (key) {
        results.push(key);
        recursive(data[key]);
        return data[key]; // This doesn't actually do anything...
      });
  }
  recursive(data);
  return results;
};

const value = flattenData(sampleData);

Here's a simple recursion:

 const deepKeys = (o) => Array.isArray (o)? o.flatMap (deepKeys): Object (o) === o? Object.entries (o).flatMap (([k, v]) => [k, ... deepKeys (v)]): [] const sampleData = {coyotes: '', armadillos: false, wombats: [''], geckos: 0, dogs: {beagle: '', bulldog: ''}, wolves: [{type: '', color: '', range: '', status: {endangered: true, protected: false}}], cats: {}} console.log (deepKeys (sampleData))
 .as-console-wrapper {max-height: 100%;important: top: 0}

We need to process a little differently for arrays, objects, and other types, but each one is fairly simple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM