Search code examples
javascriptarraysrecursiondata-structuresflatten

What are transforming approaches that collect array items from a nested data-structure into a single flat array?


Given is a nested data-structure which I want to get transformed into a single flat array of non nested array-items.

The data and the code I came up with so far are as follows ...

const data = [{
  heading: [{
    name: "Heading 01",
    Items: [{
      name: "Item 01",
      layers: [{
        name: "layer01",
        id: 4,
        parent: 3,
        droppable: false,
      }, {
        name: "layer02",
        id: 5,
        parent: 3,
        droppable: false,
      }],
      id: 3,
      parent: 2,
      droppable: true,
    }],
    id: 2,
    parent: 1,
    droppable: true,
  }],
  id: 1,
  parent: 0,
  droppable: true,
}];

const flatArray = [];
const flatObject = {};
  
for (let index = 0; index < data.length; index++) {
  for (const prop in data[index]) {

    const value = data[index][prop];

    if (Array.isArray(value)) {
      for (let i = 0; i < value.length; i++) {
        for (const inProp in value[i]) {
          flatObject[inProp] = value[i][inProp];
        }
      }
    } else {
      flatObject[prop] = value;
    }
  }
  flatArray.push(flatObject);
}

console.log(flatArray)
.as-console-wrapper { min-height: 100%!important; top: 0; }

... and the result is expected to be equal to the next provided data structure ...

[{
  id: 1,
  parent: 0,
  droppable: true,
}, {
  name: "Heading 01",
  id: 2,
  parent: 1,
  droppable: true,
}, {
  name: "Item 01",
  id: 3,
  parent: 2,
  droppable: true,
}, {
  name: "layer01",
  id: 4,
  parent: 3,
  droppable: false,
}, {
  name: "layer02",
  id: 5,
  parent: 3,
  droppable: false,
}]

Solution

  • One could come up with a recursive approach which targets specific array items by any wanted array's key/identifier which are all going to be used by a destructuring assignment with default values and rest property.

    The advantage of the destructuring is the separation and the direct access of all relevant data, the possible to be targeted array(s) and the rest of the currently processed data item.

    function collectSpecificArrayItemsRecursively(data) {
      const result = [];
    
      if (Array.isArray(data)) {
    
        result
          .push(
            ...data
              .flatMap(collectSpecificArrayItemsRecursively)
          );
      } else {
    
        const {
          // destructuring into specific
          // arrays and the data's rest.
          heading = [], Items = [], layers = [], ...rest
        } = data;
    
        result
          .push(
            rest,
            ...heading
              .concat(Items)
              .concat(layers)
              .flatMap(collectSpecificArrayItemsRecursively),
          );    
      }
      return result;
    }
    const data = [{
      heading: [{
        name: "Heading 01",
        Items: [{
          name: "Item 01",
          layers: [{
            name: "layer01",
            id: 4,
            parent: 3,
            droppable: false,
          }, {
            name: "layer02",
            id: 5,
            parent: 3,
            droppable: false,
          }],
          id: 3,
          parent: 2,
          droppable: true,
        }],
        id: 2,
        parent: 1,
        droppable: true,
      }],
      id: 1,
      parent: 0,
      droppable: true,
    }];
    
    console.log(
      collectSpecificArrayItemsRecursively(data)
    );
    .as-console-wrapper { min-height: 100%!important; top: 0; }