0

I have this JSON array tree that can include any number of nested arrays:

const namesArrayTree = [
    {
        "name": "Peter"
    },
    {
        "name": "folder1",
        "isArray": true,
        "namesArray": [
            {
                "name": "Paul"
            },
            {
                "name": "folder2",
                "isArray": true,
                "namesArray": [
                    {
                        "name": "Mary"
                    },
                    {
                        "name": "John"
                    }
                ]
            }
        ]
    },
    {
        "name": "Mark"
    }
]

I need to transform it to a flat array including only the names:

const namesArrayFlat = [ "Peter", "Paul", "Mary", "John", "Mark" ]

So I'm using this code to do the transformation:

const namesArrayTree = [
    {
        "name": "Peter"
    },
    {
        "name": "folder1",
        "isArray": true,
        "namesArray": [
            {
                "name": "Paul"
            },
            {
                "name": "folder2",
                "isArray": true,
                "namesArray": [
                    {
                        "name": "Mary"
                    },
                    {
                        "name": "John"
                    }
                ]
            }
        ]
    },
    {
        "name": "Mark"
    }
] ;

  function getNamesList(item) {
    let name = item.name;
    let isArray = item.isArray;

    if (isArray) {
      name = item.namesArray.map(getNamesList).join("\r\n");
    }
    return name;
  }

  const namesList = namesArrayTree.map(getNamesList).join("\r\n");
  const namesArrayFlat = namesList.split("\r\n");
  
  console.log(namesArrayFlat)

The code works well, but I would like to get rid of the extra steps to create a list with the names using join.("\r\n") and then convert to array using split("\r\n").

That is, I would like to reduce the code by removing the following:

     function getNamesList(item) {
        let name = item.name;
        let isArray = item.isArray;

        if (isArray) {
/* remove code to join by "\r\n" */
          name = item.namesArray.map(getNamesList) 
        }
        return name;
      }
/* remove code to create "namesList" constant and remove code to join by "\r\n") */
      const namesArrayFlat = namesArrayTree.map(getNamesList) 
      
      console.log(namesArrayFlat)

(The above code still returns a tree nested arrays structure)

Any ideas about how to get rid of the extra code? also any suggestions about how to improve the code would be great, thanks!

Andres533
  • 17
  • 8
  • Suggested way of flatten json [here](https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects) as answer to similar question. – Alex Tom May 11 '22 at 09:31

2 Answers2

1
function getNamesList(item) {
    return item.isArray ? item.namesArray.map(getNamesList) : item.name
}

const names = namesArrayTree.map(getNamesList).flat(Infinity)

console.log(names)
Dave Meehan
  • 3,133
  • 1
  • 17
  • 24
1

You can achieve this with an array reducer as follows:

const namesArray = [
  {
    "name": "Peter"
  },
  {
    "name": "folder1",
    "isArray": true,
    "namesArray": [
      {
        "name": "Paul"
      },
      {
        "name": "folder2",
        "isArray": true,
        "namesArray": [
          {
            "name": "Mary"
          },
          {
            "name": "John"
          }
        ]
      }
    ]
  },
  {
    "name": "Mark"
  }
] ;

function reduceNamesList(list, item) {
  if (item.isArray) {
    return item.namesArray.reduce(reduceNamesList, list);
  }

  list.push(item.name)

  return list
}

const namesList = namesArray.reduce(reduceNamesList, [])
console.log(namesList)
M1ke
  • 6,166
  • 4
  • 32
  • 50
  • 1
    I should add, the mechanism of using `flat` is perfectly suitable and in a way simpler, but understanding reducers is going to do you very well for other problems you'll encounter in future involving traversing nested structures. – M1ke May 11 '22 at 09:51
  • Thank you, that's a correct solution, but the other answer has less code. – Andres533 May 11 '22 at 10:09
  • Thank you for the tip about using reduce, I should had tried that to start with. – Andres533 May 11 '22 at 10:31
  • 1
    Yes that's reasonable; in JS the other answer is simpler. One thing worth bearing in mind is that this concept/requirement is by no means limited to JS, and the specific use of `flat` is less likely to transpose into other languages. Conversely, most higher level languages will have `map` and `reduce` methods for list-like objects. – M1ke May 11 '22 at 14:57