【问题标题】:flatten nested json array with named collections使用命名集合展平嵌套的 json 数组
【发布时间】:2020-11-12 07:03:49
【问题描述】:

鉴于以下 json

[
    {
        id: 'myId1',
        value: 'Tree View top level 1',
        fetchedChildren: []
    },
    {
        id: 'myId2',
        value: 'Tree View top level 2',
        fetchedChildren: [
            {
                id: 'myId3',
                value: 'Tree View second level 1',
                fetchedChildren: []
            },
            {
                id: 'myId4',
                value: 'Tree View second level 2',
                fetchedChildren: []
            },
        ]
    },
]

嵌套的命名为“fetchedChildren”的集合可以无限延续

有没有一种简单的方法可以像这样将其展平为单个数组?

[
    {
        id: 'myId1',
        value: 'Tree View top level 1',
    },
    {
        id: 'myId2',
        value: 'Tree View top level 2',
        
    },
    {
        id: 'myId3',
        value: 'Tree View second level 1',
    },
    {
        id: 'myId3',
        value: 'Tree View second level 2',
    },
]

我已经看到很多对没有命名集合的嵌套对象执行此操作的示例,但我还没有看到或无法弄清楚如何在这种情况下执行此操作

【问题讨论】:

  • 总是只有一层还是更多?
  • 更多——理论上可以永远持续下去

标签: javascript json recursion


【解决方案1】:

参数解构可以帮助我们为这种情况编写一个简单的递归:

const flatten = ([{fetchedChildren = undefined, ... rest} = {}, ... xs]) => 
  fetchedChildren == undefined
    ? []
    : [rest, ... flatten ([... xs, ... fetchedChildren])]

const ar = [{id: 'myId1', value: 'Tree View top level 1', fetchedChildren: []}, {id: 'myId2', value: 'Tree View top level 2', fetchedChildren: [{id: 'myId3', value: 'Tree View second level 1', fetchedChildren: [{id: 'myId5', value: 'Tree View thrid level 1', fetchedChildren: []}]}, {id: 'myId4', value: 'Tree View second level 2', fetchedChildren: []}]}];

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

尾递归变体并不复杂:

const flatten = ([{fetchedChildren = undefined, ... rest} = {}, ... xs], res = []) => 
  fetchedChildren == undefined
    ? res
    : flatten ([... xs, ... fetchedChildren], [...res, rest])

【讨论】:

    【解决方案2】:

    这就是你想要的:(不要使用递归,因为你可能会溢出调用堆栈,因为你说它可能有无穷多个层)

    const ar = [{
        id: 'myId1',
        value: 'Tree View top level 1',
        fetchedChildren: []
    }, {
        id: 'myId2',
        value: 'Tree View top level 2',
        fetchedChildren: [{
            id: 'myId3',
            value: 'Tree View second level 1',
            fetchedChildren: [{
                id: 'myId5',
                value: 'Tree View thrid level 1',
                fetchedChildren: []
            }]
        }, {
            id: 'myId4',
            value: 'Tree View second level 2',
            fetchedChildren: []
        }]
    }];
    
    
    for (var i = 0; i < ar.length; i++) {
        if (ar[i].fetchedChildren.length) {
            ar.push(...ar[i].fetchedChildren);
        }
        delete ar[i].fetchedChildren;
    }
    console.log(ar);

    【讨论】:

    • 你必须使用递归,因为嵌套可以任意深。
    • 正好相反,因为嵌套可以任意深,你不应该使用递归,因为调用堆栈可能会被任意溢出。
    • 好吧。数据大小必须由其他地方的编码人员管理。此外,现代编译器可以优化尾递归。据我所知,您的代码只能处理两个级别。
    • 我认为我的代码可以处理任意数量的级别(我编辑了一个额外的第三级示例)
    • 好的...我明白了。你的方法是广度优先,不是吗?它显然更节省内存。
    【解决方案3】:

    您可以减少以运行递归提取器。

    const data = [
            {
                id: 'myId1',
                value: 'Tree View top level 1',
                fetchedChildren: []
            },
            {
                id: 'myId2',
                value: 'Tree View top level 2',
                fetchedChildren: [
                    {
                        id: 'myId3',
                        value: 'Tree View second level 1',
                        fetchedChildren: []
                    },
                    {
                        id: 'myId4',
                        value: 'Tree View second level 2',
                        fetchedChildren: []
                    },
                ]
            },
        ]
        
        const extract = (acc, item) => {
          const value = Object.keys(item)
            .filter(k => k !== 'fetchedChildren')
            .map(k => ([k, item[k]]))
            .reduce((res, [k,v]) => ({...res, [k]: v}), {})
          const children = item.fetchedChildren.reduce(extract, [])
    
            
          return [...acc, value, ...children]
        }
    
        const result = data.reduce(extract, [])
    
     console.log(data)
     console.log(result)

    【讨论】:

      【解决方案4】:

      您可以采用flatMap 方法并通过从对象中解构子项来获取所有子项。

      var getFlat = ({ fetchedChildren, ...o }) => [o, ...fetchedChildren.flatMap(getFlat)],
          data = [{ id: 'myId1', value: 'Tree View top level 1', fetchedChildren: [] }, { id: 'myId2', value: 'Tree View top level 2', fetchedChildren: [{ id: 'myId3', value: 'Tree View second level 1', fetchedChildren: [] }, { id: 'myId4', value: 'Tree View second level 2', fetchedChildren: [] }] }],
          flat = data.flatMap(getFlat);
      
      console.log(flat);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

        【解决方案5】:

        递归是在树上进行任何深度优先搜索的方式:

        let arr=[
            {
                id: 'myId1',
                value: 'Tree View top level 1',
                fetchedChildren: []
            },
            {
                id: 'myId2',
                value: 'Tree View top level 2',
                fetchedChildren: [
                    {
                        id: 'myId3',
                        value: 'Tree View second level 1',
                        fetchedChildren: []
                    },
                    {
                        id: 'myId4',
                        value: 'Tree View second level 2',
                        fetchedChildren: []
                    },
                ]
            },
        ];
        
        function flatten(a){
            var result=[];
            for (let e of a) {
               result.push({id:e.id,value:e.value})
               result=result.concat(flatten(e.fetchedChildren));
            }
            return result;
        }
        
        console.log(flatten(arr));

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-31
          • 2020-04-15
          • 1970-01-01
          • 2022-01-08
          • 2021-10-12
          • 1970-01-01
          • 2017-12-26
          相关资源
          最近更新 更多