C# 副作用最小的递归

C# 副作用最小的递归,c#,recursion,side-effects,C#,Recursion,Side Effects,所以我有一棵有孩子的人的树,我只想让有车的人。如果一个孩子有一辆车,但父母没有,我想让父母留在树上 我认为最好的方法是使用递归函数,如下所示: private Person CheckPerson(Person person) { List<Person> removeList = new List<Person>(); foreach (Person child in Person.Children) { if (CheckPe

所以我有一棵有孩子的人的树,我只想让有车的人。如果一个孩子有一辆车,但父母没有,我想让父母留在树上

我认为最好的方法是使用递归函数,如下所示:

private Person CheckPerson(Person person)
{
    List<Person> removeList = new List<Person>();

    foreach (Person child in Person.Children)
    {
        if (CheckPerson(child) == null)
        {
            // I can't remove the children here because
            // they are used in the foreach loop
            removeList.Add(child);
        }

    }

    foreach (Person removable in removeList)
    {
        Person.Children.Remove(removable);
    }

    if (person.Children.Count() > 0)
    {
        return person;
    }
    else if (person.cars.Count() > 0)
    {
        return person;
    }
    else
    {
        return null;
    }
}
public IEnumerable<Person> GetPersonsWithCars(Person person)
{
    var personReturned = false;
    if (person.Cars.Any())
    {
        yield return person;
        personReturned = true;
    }

    foreach (var child in person.Children)
    {
         foreach (var item in GetPersonsWithCars(child))
         {
             if (!personReturned)
             {
                 yield return person;
                 personReturned = true;
             }

             yield return item;
         }
    }
}
私人支票人(个人)
{
List removeList=新列表();
foreach(人-子-人-子-子)
{
if(CheckPerson(child)==null)
{
//我不能带走这里的孩子,因为
//它们用于foreach循环
removeList.Add(子级);
}
}
foreach(移除列表中可移除的人员)
{
人。儿童。移除(可移动);
}
if(person.Children.Count()>0)
{
返回人;
}
else if(person.cars.Count()>0)
{
返回人;
}
其他的
{
返回null;
}
}
但是这样我确实改变了参数person,我移除了他的孩子

我尝试的其他方法如下

  • 退票无效
  • 返回布尔
  • 参考参数
我还尝试在没有返回值的情况下进行操作,只是查看输入人员的结果,但这并没有保存更改

返回bool以确定是否应该删除子对象是可行的,但原始方法调用对bool没有任何用处。所以这个方法从Person->bool开始就有副作用,但我还是换了人

使用ref参数时,我无法编译,因为我删除了子项,并在foreach循环中更改了对象


因此,我想知道使用副作用最小的递归方法的最佳方法是什么,或者最佳实践是什么?

如果您只需要测试车辆是否可用,您可以使用以下方法:

public Person CheckPerson(Person person)
{
    return person.Cars.Any() || person.Children.Any(x => CheckPerson(x) != null) ? person : null;                    
}
但我认为您应该返回一个
IEnumerable
,其中包含所有拥有汽车的人(或一个孩子拥有汽车)

也许是这样的:

private Person CheckPerson(Person person)
{
    List<Person> removeList = new List<Person>();

    foreach (Person child in Person.Children)
    {
        if (CheckPerson(child) == null)
        {
            // I can't remove the children here because
            // they are used in the foreach loop
            removeList.Add(child);
        }

    }

    foreach (Person removable in removeList)
    {
        Person.Children.Remove(removable);
    }

    if (person.Children.Count() > 0)
    {
        return person;
    }
    else if (person.cars.Count() > 0)
    {
        return person;
    }
    else
    {
        return null;
    }
}
public IEnumerable<Person> GetPersonsWithCars(Person person)
{
    var personReturned = false;
    if (person.Cars.Any())
    {
        yield return person;
        personReturned = true;
    }

    foreach (var child in person.Children)
    {
         foreach (var item in GetPersonsWithCars(child))
         {
             if (!personReturned)
             {
                 yield return person;
                 personReturned = true;
             }

             yield return item;
         }
    }
}
public IEnumerable GetPersonWithCars(个人)
{
var personReturned=false;
if(person.Cars.Any())
{
收益人;
personReturned=true;
}
foreach(var child-in-person.childs)
{
foreach(GetPersonWithCars中的var项(子))
{
如果(!personReturned)
{
收益人;
personReturned=true;
}
收益回报项目;
}
}
}

如果孩子的孩子有车怎么办?你把所有的父母都留下了吗?或者仅仅是第一级?从树叶开始,一找到包含树枝的汽车就开始工作。@Thomas我想从树根(也就是最老的祖父母)导航到所有有汽车的人。所以我需要中间的每一步来保持树结构的活力???没有。但是?:操作员将返回它
.Any()
.Count()>0
完全相同,但没有迭代所有项目以获得实际计数。它只测试是否存在项。在下面的示例中,树结构不会消失吗?我试过上面的例子,效果很好,但我不确定它是如何工作的。为什么没有车的孩子们要搬走?(我想要这个,但我不太明白)是的,你会失去树的结构。第二个示例对所有项进行迭代,并返回子树中具有汽车的所有项。您将获得一个所有项目的平面“列表”,而不是一个树,但在大多数情况下,您将为符合您的条件的每个项目执行一个操作。在这种情况下,您不需要知道如何遍历树。您将在一个简单的可枚举列表中获得所有项目。如果您喜欢第一个或第二个示例,这取决于您的需要。