0

I am trying to solve this question it needs me to flatten this object parent that it has children each parent has 2 children, and each child has 2 children and so on....

My goal is to flatten this to one single object.

const par = {
    id: 1,
    name: "parent",
    children: [{
        id: 2,
        name: "child 1",
        children:[{
            id: 4,
            name: "child 3",
            children: [],
        },{
            id: 5,
            name: "child 4 ",
        }]
    },{
        id: 3,
        name: "child 2",
        children: [{
            id: 6,
            name: "child 5",
        },{
            id: 7,
            name: "child 6",
            children: []
        }]
    }]
}

I tried function, but it returns an array from Deep Flatten JavaScript Object Recursively

function flat(r, a) {
    let b = {};
    Object.keys(a).forEach(function (k) {
        if (k !== 'children') {
            b[k] = a[k];
        }
    });
    r.push(b);
    if (Array.isArray(a.children)) {
        b.children = a.children.map(function (a) { return a.id;});
        return a.children.reduce(flat, r);
    }
    return r;
}

3
  • 4
    What's the expected output of the above? Commented Sep 12, 2022 at 18:01
  • thanks for reminding me let me add it to the question Commented Sep 12, 2022 at 18:01
  • Do you want as a result an array of all family members or what? Commented Sep 12, 2022 at 18:12

4 Answers 4

3

Here's an effective technique using a recursive generator flat -

function *flat({ children = [], ...t }, parentId = null) {
  yield { ...t, parentId }
  for (const child of children)
    yield *flat(child, t.id)
}

const par = {id: 1,name: "parent",children: [{id: 2,name: "child 1",children:[{id: 4,name: "child 3",children: [],},{id: 5,name: "child 4 ",}]},{id: 3,name: "child 2",children: [{id: 6,name: "child 5",},{id: 7,name: "child 6",children: []}]}]}

console.log(Array.from(flat(par)))
.as-console-wrapper { min-height: 100%; top: 0; }

You can collect all the results of a generator using Array.from -

[
  {
    "id": 1,
    "name": "parent",
    "parentId": null
  },
  {
    "id": 2,
    "name": "child 1",
    "parentId": 1
  },
  {
    "id": 4,
    "name": "child 3",
    "parentId": 2
  },
  {
    "id": 5,
    "name": "child 4 ",
    "parentId": 2
  },
  {
    "id": 3,
    "name": "child 2",
    "parentId": 1
  },
  {
    "id": 6,
    "name": "child 5",
    "parentId": 3
  },
  {
    "id": 7,
    "name": "child 6",
    "parentId": 3
  }
]

Or you can simply iterate thru the generator's result directly -

for (const flatNode of flat(par)) {
  // do something with flatNode ...
}

See this related Q&A for a technique to convert the flat tree back to a recursive tree or graph.

Sign up to request clarification or add additional context in comments.

Comments

2

You still owe us a description of your desired output. But if you want something as simple as this:

[
    {id: 1, name: "parent"},
    {id: 2, name: "child 1"},
    {id: 4, name: "child 3"},
    {id: 5, name: "child 4"},
    {id: 3, name: "child 2"},
    {id: 6, name: "child 5"},
    {id: 7, name: "child 6"}
]

Then a depth-first recursive function can be as simple as this:

const flatten = ({children = [], ...rest}) => [rest, ...children .flatMap (flatten)]

const par = {id: 1, name: "parent", children: [{id: 2, name: "child 1", children: [{id: 4, name: "child 3", children: []}, {id: 5, name: "child 4 ", }]}, {id: 3, name: "child 2", children: [{id: 6, name: "child 5", }, {id: 7, name: "child 6", children: []}]}]}

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

If you wanted to include a parentId field, using null for root-level objects, it's only slightly more complex:

const flatten = ({id, children = [], ...rest}, parentId = null) => [
  {id, ...rest, parentId}, ...children .flatMap (c => flatten(c, id))
]

Comments

1

You can try this

function flatTree(tree, parentId = null) {
  const { id, name, children } = tree;
  const result = [{ id, name, parentId }];
  if (Array.isArray(children)) {
    children.forEach((child) => {
      result.push(...flatTree(child, id));
    });
  }
  return result;
}

const par = {
  id: 1,
  name: "parent",
  children: [
    {
      id: 2,
      name: "child 1",
      children: [
        {
          id: 4,
          name: "child 3",
          children: [],
        },
        {
          id: 5,
          name: "child 4 ",
        },
      ],
    },
    {
      id: 3,
      name: "child 2",
      children: [
        {
          id: 6,
          name: "child 5",
        },
        {
          id: 7,
          name: "child 6",
          children: [],
        },
      ],
    },
  ],
};

console.log(flatTree(par));

/**
 * Output:
 * [
  { id: 1, name: 'parent', parentId: null },
  { id: 2, name: 'child 1', parentId: 1 },
  { id: 4, name: 'child 3', parentId: 2 },
  { id: 5, name: 'child 4 ', parentId: 2 },
  { id: 3, name: 'child 2', parentId: 1 },
  { id: 6, name: 'child 5', parentId: 3 },
  { id: 7, name: 'child 6', parentId: 3 }
]
 */

Comments

0

Here is a solution using object-scan. Reinventing the wheel is typically not as bug-free, flexible or maintainable as using a battle-tested library!

.as-console-wrapper {max-height: 100% !important; top: 0}
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.min.js';

const par = { id: 1, name: 'parent', children: [{ id: 2, name: 'child 1', children: [{ id: 4, name: 'child 3', children: [] }, { id: 5, name: 'child 4 ' }] }, { id: 3, name: 'child 2', children: [{ id: 6, name: 'child 5' }, { id: 7, name: 'child 6', children: [] }] }] };

const fn = objectScan(['**{children[*]}.id'], {
  rtn: ({ parent: { id, name } }) => ({ id, name })
});

const r = fn(par);
console.log(r);
/* => [
  { id: 7, name: 'child 6' },
  { id: 6, name: 'child 5' },
  { id: 3, name: 'child 2' },
  { id: 5, name: 'child 4 ' },
  { id: 4, name: 'child 3' },
  { id: 2, name: 'child 1' },
  { id: 1, name: 'parent' }
] */
</script>

Disclaimer: I'm the author of object-scan

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.