Javascript递归:删除只有一个孩子的关卡

时间:2019-03-13 10:16:58

标签: javascript recursion ecmascript-6

给出以下数据结构:

[  
  {  
     "name":"root",
     "children":[  
        {  
           "name":"de",
           "children":[  
              {  
                 "name":"de",
                 "children":[
                    {  
                       "name":"project-1",
                       "children":[  
                       ]
                    },
                    {  
                       "name":"project-2",
                       "children":[  
                       ]
                    }
                 ]
              }
           ]
        }
     ]
  }
]

预期:

[
  {
     "name":"project-1",
     "children":[
     ]
  },
  {
     "name":"project-2",
     "children":[
     ]
  }
]

如果只有一个孩子,我想删除一个关卡。在此示例中,我想要一个新数组,其中仅包含“ root”级别的子级,而没有root本身。

我会用reduce来做到这一点,但仍然无法将reduce与递归结合起来。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

  

之后,您可以简单地使用map和flatten数组。

.map(o => o.children).flat()

编辑:找出真实问题后,更新答案
仍然可以以递归的方式使用map和flatten逻辑。

function removeSingleChildElms (o) {
  if (!o.children) return

  if (o.children.length === 1) {
      return o.children.map(removeSingleChildElms).flat()
  } else {
    return o.children
  }
}

EDIT2: 一些解释:问题是将对象数组转换为不同对象的数组。我不选择减少,因为问题不关心同级元素之间的关系/逻辑。这只是为了进行转换,因此地图将足以正常工作。

问题要求“跳过”有1个孩子的对象。这是重复出现的部分,这意味着:如果看到满足此条件的对象,则可以进行更深入的映射。在任何其他有效条件下,孩子都保持不变(否则)

答案 1 :(得分:0)

通过将任务分为两部分,可以轻松进行树转换:

  1. 用于转换单个节点的功能
  2. 用于转换节点的数组的函数

要转换单个节点,我们编写transform1

  • 如果没有 个孩子,我们找到了一个叶子节点,返回单例节点
  • 如果只有一个 子代,则删除该节点并返回其唯一子代的转换
  • 否则,该节点有多个子节点,请调用第二个函数transformAll
const transform1 = ({ children = [], ...node }) =>
  children.length === 0         // leaf
    ? [ node ]
: children.length === 1         // singleton
    ? transform1 (...children)
: transformAll (children)       // default

要转换节点数组,我们写transformAll-

const transformAll = (arr = []) =>
  arr .flatMap (transform1)

如您所见,transformAll调用transform1,也调用transformAll。这种技术称为mutual recursion,是处理递归数据结构(如您在问题中提出的结构)的好方法。

为了确保我们的功能正常工作,我修改了树以包含更多数据方案。请注意,我们的程序适用于具有children属性的任何节点。所有其他属性都显示在结果中-

const data =
  [ { name: "a"
    , children:
        [ { name: "a.a"
          , children: 
              [ { name: "a.a.a"
                , children: []
                }
              , { name: "a.a.b"
                , foo: 123
                , children: []
                }
              ]
          }
        ]
    }
  , { name: "b"
    , children:
        [ { name: "b.a"
          , children: 
              [ { name: "b.a.a"
                , children: []
                }
              , { name: "b.a.b"
                , children: []
                }
              ]
          }
        , { name: "b.b"
          , children: []
          }
        ]
    }
  , { name: "c"
    , children: []
    }
  ]

我们可以对您的数据运行transformAll来转换所有个节点-

transformAll (data)
// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// , { name: 'b.a.a' }
// , { name: 'b.a.b' }
// , { name: 'b.b' }
// , { name: 'c' }
// ]

或者要转换单个节点,我们称为transform1-

transform1 (data[0])
// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// ]

transform1 (data[2])
// [ { name: 'c' } ]

展开以下代码段,以在您自己的浏览器中验证结果-

const data =
  [ { name: "a"
    , children:
        [ { name: "a.a"
          , children: 
              [ { name: "a.a.a"
                , children: []
                }
              , { name: "a.a.b"
                , foo: 123
                , children: []
                }
              ]
          }
        ]
    }
  , { name: "b"
    , children:
        [ { name: "b.a"
          , children: 
              [ { name: "b.a.a"
                , children: []
                }
              , { name: "b.a.b"
                , children: []
                }
              ]
          }
        , { name: "b.b"
          , children: []
          }
        ]
    }
  , { name: "c"
    , children: []
    }
  ]

const transform1 = ({ children = [], ...node }) =>
  children.length === 0         // leaf
    ? [ node ]
: children.length === 1         // singleton
    ? transform1 (...children)
: transformAll (children)       // default

const transformAll = (arr = []) =>
  arr .flatMap (transform1)

console .log (transformAll (data))

// [ { name: 'a.a.a' }
// , { name: 'a.a.b', foo: 123 }
// , { name: 'b.a.a' }
// , { name: 'b.a.b' }
// , { name: 'b.b' }
// , { name: 'c' }
// ]