Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/438.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript:在递归之间需要一个共享数组来将结果推送到_Javascript_Recursion_Tree - Fatal编程技术网

JavaScript:在递归之间需要一个共享数组来将结果推送到

JavaScript:在递归之间需要一个共享数组来将结果推送到,javascript,recursion,tree,Javascript,Recursion,Tree,有一个数组,其中有一个家谱,其中有人的名字,他们的性别和他们的父母(父亲和母亲)的名字 现在,我(未成功)尝试列出这个家庭中一个人的所有孩子的名字: 函数所有子项(父项){ var children=祖先.filter( 职能(人){ 如果(parent.sex='m'){ return person.father==parent.name }否则{ return person.mother==parent.name } } ) if(children.length==0){ console.l

有一个数组,其中有一个家谱,其中有人的名字,他们的性别和他们的父母(父亲和母亲)的名字

现在,我(未成功)尝试列出这个家庭中一个人的所有孩子的名字:

函数所有子项(父项){
var children=祖先.filter(
职能(人){
如果(parent.sex='m'){
return person.father==parent.name
}否则{
return person.mother==parent.name
}
}
)
if(children.length==0){
console.log(parent.name);
}否则{
儿童。forEach(所有儿童);
}
}
目前,这是唯一的控制台记录的人谁没有孩子。 问题是,我需要将每个子对象推入一个结果数组,但我使用的是递归,所以我不能在所有递归之间共享一个结果变量


(当然,我还应该检查是否以前没有推过相同的名称-假设没有重复-这不是我的问题,我知道如何做,我的问题是获得一个结果数组,逐步填充递归步骤(每个递归步骤可以推送其中的一个元素))。

现在使用范围函数

function allChildren(parent) {
  var getChildrenRecursive = function(parent, elements){
    var children = ancestors.filter(
      function(person) {
        if (parent.sex == 'm') {
          return person.father == parent.name
        } else {
          return person.mother == parent.name
        }
      }
    )
    if (children.length == 0) {
      console.log(parent.name);
    } else {
      elements = elements.concat(children);
      children.forEach(function(child){elements = elements.concat(getChildrenRecursive(child, elements));})
      return elements;
    }
  };

  return getChildrenRecursive(parent, []);
}

下面是一个简单的方法(如果您可以使用arrow函数和数组解构,但您还是得到了这个想法):

我和你有关系

使用尾部递归有什么问题?那会让你的生活更轻松

我所做的是编写一个函数,用尾部递归完成任务。通过使用第二个参数作为数据持有者,可以通过递归树传递数据数组。关于尾部递归的更多信息可以在本文中找到:

我已经创建了一个函数(底部的交互式示例)

children=[]
表示如果未提供任何参数,则将数组
[]
用作默认参数。这个概念很简单。因此,在递归树的开头,您只需使用
showChildrenOf(person)
调用函数,就可以得到其所有后代的数组。在函数体中,我正在填充
子对象
,如果该人有子对象。然后,我使用showChildrenOf(child,childrenof)再次调用该函数,以便下一个函数调用与该子函数一起进行,以检查他是否有子函数和填充的数组作为数据持有者。由于我提供了一个参数,下一个函数处理的是
子类=[…]
,而不是空数组

const人员=
[
{姓名:“我是谁”,父亲:“德克斯·鲍勃”,母亲:“爱丽丝·马尼亚”,g:“m”}
,{姓名:'Mic Mac',父亲:'我是谁',母亲:'Mega Wonder',g:'m'}
,{姓名:'Ani Mani',父亲:'Bob Y',母亲:'Women Wonder',g:'f'}
,{姓名:'Jan Jot',父亲:'我是谁',母亲:'Wunder Bra',g:'m'}
,{姓名:'Kit Kat',父亲:'Jan Jot',母亲:'Unknown',g:'m'}
,{姓名:'Tiny Bell',父亲:'Kit Kat',母亲:'Unknown',g:'f'}
,{姓名:'Bill Kid',父亲:'Kit Kat',母亲:'Unknown',g:'m'}
,{名字:'Billy Wuz',父亲:'Oreos Oo',母亲:'Tiny Bell',g:'m'}
];
函数showChildrenOf(person,childrenof=[]){
const tmp=persons.filter(p=>(person.g=='m'?person.name==p.father:person.name==p.mother));
if(tmp.长度){
//有孩子
儿童。推(…tmp);
forEach(child=>showChildrenOf(child,childs));
}
否则{
//没有孩子:什么都不做
}
返回儿童;
}
console.log(showChildrenOf(persons[0]);//展示“我是谁”的孩子们

console.log(showChildrenOf(persons[1]);//显示“Mic Mac”儿童
以下是我自己想出的解决方案,效果很好。它使用递归函数,还使用JavaScript中的闭包概念

因此,我将递归逻辑(我在前面的问题中提到过)包装在主函数(名为“allChildren”)内的一个单独的内部函数(名为“all”-我知道名称很快也很糟糕-)中:

尽管事实上,这在现实中是一个无用的功能。这只是我感兴趣的个人好奇心,我这样做是为了学习更多关于递归的知识。很明显,在家谱的几代人中重复一个全名是很常见的事情

最后,使用提供的数据调用此函数,如下所示:

  console.log(allChildren(byName['Pauwels van Haverbeke'])); //byName is just a simple map from names to objects of the family tree. I haven't put the definition for the sake of brevity.
成功地给出了以下结果:

(24) ["Lieven van Haverbeke", "Pieter Haverbeke", "Lieven Haverbeke", "Willem Haverbeke", "Daniel Haverbeke", "Jan Haverbeke", "Pieter Bernard Haverbeke", "Angela Haverbeke", "Jan Francies Haverbeke", "Pieter Antone Haverbeke", "Carel Haverbeke", "Carolus Haverbeke", "Emile Haverbeke", "Philibert Haverbeke", "Maria Haverbeke", "Livina Haverbeke", "Bernardus de Causmaecker", "Petronella de Decker", "Joanna de Causmaecker", "Maria van Brussel", "Elisabeth Haverbeke", "Laurentia Haverbeke", "Jacobus Bernardus van Brussel", "Jan Frans van Brussel"]

这里有一个类似于KarelG的方法。尽管如此,它的不同程度足以证明它自己的答案

分歧
  • 这个函数将祖先作为参数传递,而不是将它们作为自由变量保留在函数中。自由变量使代码更难理解,也更难测试

  • 它将递归函数从公共函数中分离出来,将它们保持在一个闭包中。这是一种不太常见的技术,现在人们在许多地方使用某种模块,但它仍然很有用,特别是在web上。这就是
    (()=>{/*…返回一些函数*/})(
    语法

  • 它使用一个集合作为递归累加器,以避免重复

  • 它忽略了性别。我看不出检查它的理由。如果孩子说母亲是某某,我看不出有任何必要重复检查‘mother.sex==='f'`。我可能错过了什么

  • 虽然它保留了现有的提供完整person对象并返回姓名列表的API,但将其切换为仅提供姓名或返回人员列表相对容易。下面将详细介绍

  • 我把它命名为
    allgrounds
    ,因为这似乎比
    allChildren
    更准确

代码
constalldegents=(()=>{
const all=(家族、姓名、子女=新集合())=>{
const kids=family.filter(p=>p.father==name | | p.mother==name).map(k=>k.name)
kids.forEach(kid=>(childs.add(kid)),all(family,kid,child
function allChildren(parent) {
    var firstParentName = parent.name;
    var allChildrenArray = [];

    function all(parent) {
        var children = ancestors.filter(
            function(person) {
                if (parent.sex == 'm') {
                    return person.father == parent.name
                } else {
                    return person.mother == parent.name
                }
            }
        )
        if (children.length == 0) {
            if (allChildrenArray.indexOf(parent.name) == -1 &&
                parent.name != firstParentName) {
                allChildrenArray.push(parent.name);
            }
            return allChildrenArray;
        } else {
            children.map(function(child) {
                if (allChildrenArray.indexOf(child.name) == -1) {
                    allChildrenArray.push(child.name);
                }
            });
            children.forEach(all);
            return allChildrenArray;
        }
    }

    return all(parent);
}
  console.log(allChildren(byName['Pauwels van Haverbeke'])); //byName is just a simple map from names to objects of the family tree. I haven't put the definition for the sake of brevity.
(24) ["Lieven van Haverbeke", "Pieter Haverbeke", "Lieven Haverbeke", "Willem Haverbeke", "Daniel Haverbeke", "Jan Haverbeke", "Pieter Bernard Haverbeke", "Angela Haverbeke", "Jan Francies Haverbeke", "Pieter Antone Haverbeke", "Carel Haverbeke", "Carolus Haverbeke", "Emile Haverbeke", "Philibert Haverbeke", "Maria Haverbeke", "Livina Haverbeke", "Bernardus de Causmaecker", "Petronella de Decker", "Joanna de Causmaecker", "Maria van Brussel", "Elisabeth Haverbeke", "Laurentia Haverbeke", "Jacobus Bernardus van Brussel", "Jan Frans van Brussel"]