Home > Software design >  Nested array transform with array without nesting
Nested array transform with array without nesting

Time:10-08

Сan someone help with the algorithm? I get an array with objects that has arrays and so on. and i want to make one array without nested elements I can get unlimited number of nested array

const test = [
    {
    id: "1",
    title: "test1",
    description: "some text",
    child: [
        {
        id: "2",
        title: "test2",
        description: "some text2",
        child: [
          {
            id: "4",
            title: "test4",
            description: "some text4",
            child: [
              {
                id: "5",
                title: "test5",
                description: "some text5",
              }
            ]
          }
        ]
      }, 
      {
        id: "3",
        title: "test3",
        description: "some text3",
      }
    ]
  }
]

I should get an array with element level Should be something like this:

const order = [
    {
    id: "1",
    title: "test1",
    description: "some text",
    url: 'test1',
    level: 1
  },
  {
    id: "2",
    title: "test2",
    description: "some text2",
    url: 'test1/test2',
    level: 2
  },
  {
    id: "4",
    title: "test4",
    description: "some text4",
    url: 'test1/test2/test4',
    level: 3
  },
  {
    id: "5",
    title: "test5",
    description: "some text5",
    url: 'test1/test2/test4/test5',
    level: 4
  },
  {
    id: "3",
    title: "test3",
    description: "some text3",
    url: 'test1/test3',
    level: 2
  }
]

Can someone help me please

CodePudding user response:

This is a pre-order traversal that keeps track of the depth and path it took. Each time there are more children, we increase the depth and add the title of the child to the path.

const data = [{id:"1",title:"test1",description:"some text",child:[{id:"2",title:"test2",description:"some text2",child:[{id:"4",title:"test4",description:"some text4",child:[{id:"5",title:"test5",description:"some text5"}]}]},{id:"3",title:"test3",description:"some text3"}]}];

function flatten(root, acc = [], depth = 1, path = []) {
    acc.push({
        id: root.id,
        title: root.title,
        description: root.description,
        url: path.concat(root.title).join("/"),
        level: depth,
    });
      
    if (root.child)
        root.child.forEach((c) => flatten(c, acc, depth   1, path.concat(root.title)));
   
    return acc;
}

console.log(data.flatMap((e) => flatten(e)));

This function is meant for a single node, and since you have an array of them, I have used flatMap in case you add more nodes to data.

CodePudding user response:

You could take a recusive approach with Array#flatMap.

const
    flat = (array = [], level = 1, u = '') => array.flatMap(({ child = [], ...item }) => {
        const url = u   (u && '/')   item.title;
        return [{ ...item, level, url }, ...flat(child, level   1, url)]
    }),
    data = [{ id: "1", title: "test1", description: "some text", child: [{ id: "2", title: "test2", description: "some text2", child: [{ id: "4", title: "test4", description: "some text4", child: [{ id: "5", title: "test5", description: "some text5" }] }] }, { id: "3", title: "test3", description: "some text3" }] }],
    result = flat(data);

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

CodePudding user response:

let's write a simple function for this

function simplify (arr) {
let returnArr = [];

const recursive = (array, level) => {

    array.forEach((item, index) => {
       let arrayObj = {level: level};

       Object.keys(item).forEach((key, index) => {
          if(!Array.isArray(item[key])){
             arrayObj[key] = item[key];
          }else{
             recursive(item[key], level   1)
          }
       })

       returnArr.push(arrayObj)
    })
 }
recursive(arr, 1)

return returnArr
}

this should do the trick, let me know if it worked for you :)

CodePudding user response:

You'll want to recursively go through your object and iterate each child until your full array is built up.

Additionally, you'll need to keep track of several things along the way: the level (depth), the url, and your final return array. Often times for recursive functions, you have a "private" function that does the real work, and a small function that exposes a reduced API. In JS, you can use an IIFE to create a closure so this private method can't be accessed.

Here is my solution:

const flattenObj = (() => {
  const _flattenObj = (obj, result, level, url) => {
    level  ;

    // Only add a `/` if we have some length to our URL
    let currentUrl = url ? `${url}/${obj.title}` : obj.title;

    const newObj = {
      id: obj.id,
      title: obj.title,
      description: obj.description,
      url: currentUrl,
      level,
    };

    // Add the new object to our return array, which maintains the same reference
    result.push(newObj);

    if (obj.child) {
      // Recursively iterate the children if they exist
      for (let child of obj.child) {
        _flattenObj(child, result, level, currentUrl);
      }
    }

    // Finally, return our full array
    return result;
  };

  // The real function we'll be calling, which initializes the extra arguments
  return obj => {
    return _flattenObj(obj, [], 0, '');
  };
})();

console.log(
  flattenObj({
    id: '1',
    title: 'test1',
    description: 'some text',
    child: [
      {
        id: '2',
        title: 'test2',
        description: 'some text2',
        child: [
          {
            id: '4',
            title: 'test4',
            description: 'some text4',
            child: [
              {
                id: '5',
                title: 'test5',
                description: 'some text5',
              },
            ],
          },
        ],
      },
      {
        id: '3',
        title: 'test3',
        description: 'some text3',
      },
    ],
  })
);

  • Related