最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Flatten array of objects with nested children - Stack Overflow

programmeradmin1浏览0评论

I've been trying to create a generic function which could flatten an array of objects but am failing at every turn. JS isn't my home language. Does anyone know of any existing function which could accept an array of nested objects and output a flattened one?

Input:

const arr = [
    {path:'/foo', ponent: SomeComponent, children: [
            {path:'/one', ponent: SomeComponent},
            {path:'/two', ponent: SomeComponent},
            {path:'/three', ponent: SomeComponent},
    ]},
    {path: '/bar', ponent: SomeComponent}
]

Expected output:

const flattened_arr = [
    {path:'/foo', ponent: SomeComponent},
    {path:'/foo/one', ponent: SomeComponent},
    {path:'/foo/two', ponent: SomeComponent},
    {path:'/foo/three', ponent: SomeComponent},
    {path:'/bar', ponent: SomeComponent},
]

I've been trying to create a generic function which could flatten an array of objects but am failing at every turn. JS isn't my home language. Does anyone know of any existing function which could accept an array of nested objects and output a flattened one?

Input:

const arr = [
    {path:'/foo', ponent: SomeComponent, children: [
            {path:'/one', ponent: SomeComponent},
            {path:'/two', ponent: SomeComponent},
            {path:'/three', ponent: SomeComponent},
    ]},
    {path: '/bar', ponent: SomeComponent}
]

Expected output:

const flattened_arr = [
    {path:'/foo', ponent: SomeComponent},
    {path:'/foo/one', ponent: SomeComponent},
    {path:'/foo/two', ponent: SomeComponent},
    {path:'/foo/three', ponent: SomeComponent},
    {path:'/bar', ponent: SomeComponent},
]
Share Improve this question asked Nov 18, 2019 at 6:15 enchanceenchance 30.6k35 gold badges94 silver badges139 bronze badges 1
  • Check out this: stackoverflow./q/44134212/4636715 – vahdet Commented Nov 18, 2019 at 6:18
Add a ment  | 

4 Answers 4

Reset to default 2

So there's Array.prototype.flat, but that doesn't deal with lists of Objects where one key (how should it know, which) should be flattened.

But you can always resort to Array.prototype.reduce to achieve that yourselves:

const SomeComponent = 'SomeComponent';
const arr = [
    {path:'/foo', ponent: SomeComponent, children: [
            {path:'/one', ponent: SomeComponent},
            {path:'/two', ponent: SomeComponent},
            {path:'/three', ponent: SomeComponent}
    ]},
    {path: '/bar', ponent: SomeComponent}
];

function myFlat(a, prefix = '') {  
  return a.reduce(function (flattened, {path, ponent, children}) {
    path = prefix + path;
    
    return flattened
      .concat([{path, ponent}])
      .concat(children ? myFlat(children, path) : []);
  }, []);
}

console.log(myFlat(arr));

For the example above, this should do.

const result = []
arr.map((obj) => {
  if (obj.children) {
    const el = {...obj, ...{}}
    delete el.children
    result.push(el) 
    Object.values(obj.children).map((v, i) => {
      result.push(v)
    })
  } else {
    result.push(obj)
  }
})

console.log(result)

You can try this

flattenArr = arr => {
    const result = [];
    arr.forEach(item => {
        const {path, ponent, children} = item;
        result.push({path, ponent});
        if (children)
            result.push(...flattenArr(children));
    });
    return result;
}

I recently had to solve this problem to create a nested dropdown and here is my solution in case some one need to have the parents history tracked to do things like

and also be able to send back to the Back-End every ID that is necessary

I am sharing the pure flatten and flatten on steroids version to record the parents

P.P.S. the code can easily be reused to create "path" just concat the data you need instead of keeping it an array as I had to do.

const items = [
  { id: 1, title: 'one', children: [{ id: 3, title: 'one`s child', children: [] }] },
  { id: 2, title: 'two', children: [] },
  {
    id: 4,
    title: 'three',
    children: [
      {
        id: 5,
        title: 'three`s child',
        children: [
          {
            id: 6,
            title: 'three`s grandchild',
            children: [{ id: 7, title: 'three`s great-grandchild', children: [] }],
          },
        ],
      },
    ],
  },
]

/**
 * @param items - [{..., children: ...}]
 * @info children key is remove and parents is set instead
 * @returns flatten array and remember parents in array
 */
const deepFlattenRememberParents = (items) => {
  const flatten = JSON.parse(JSON.stringify(items)) // Important - create a deep copy of 'items' / preferably use lodash '_.cloneDeep(items)', but for the example this will do
  for (let i = 0; i < flatten.length; i++) {
    if (flatten[i].hasOwnProperty('children')) {
      flatten[i].children.map((child) => {
        if (flatten[i].hasOwnProperty('parents')) {
          child.parents = [...flatten[i].parents, flatten[i]]
        } else {
          child.parents = [flatten[i]]
        }
        return child
      })

      flatten.splice(i + 1, 0, ...flatten[i].children)
      delete flatten[i].children
    }

    if (!flatten[i].hasOwnProperty('parents')) {
      flatten[i].parents = []
    }
  }

  return flatten
}

/**
 * @param items - [{..., children: ...}]
 * @returns flatten array
 */
const deepFlatten = (items) => {
  const flatten = JSON.parse(JSON.stringify(items)) // Important - create a deep copy of 'items' / preferably use lodash '_.cloneDeep(items)', but for the example this will do
  for (let i = 0; i < flatten.length; i++) {
    if (flatten[i].hasOwnProperty('children')) {
      flatten.splice(i + 1, 0, ...flatten[i].children)
      delete flatten[i].children
    }
  }

  return flatten
}

console.log('deepFlattenRememberParents ', deepFlattenRememberParents(items))
console.log('deepFlatten ', deepFlatten(items))

发布评论

评论列表(0)

  1. 暂无评论