具有最小副作用的递归

时间:2015-06-17 08:53:13

标签: c# recursion side-effects

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

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

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;
    }
}

但是这样我确实更改了参数人,我删除了他的孩子。

我尝试的其他方式如下。

  • return void
  • return bool
  • ref参数

我也尝试过没有返回值,只是回头查看结果的输入人员,但这并没有保存更改。

返回bool以确定是否应该删除子项,但原始方法调用对bool没有任何用处。因此,该方法具有副作用,因为Person - &gt;布尔,但我仍然改变了这个人

使用ref参数我无法编译,因为我删除了子节点并在那里更改了foreach循环中的对象。

所以我想知道使用具有最小副作用的递归方法或最佳实践是什么的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

如果您只需要测试汽车是否可用,您可以使用:

public Person CheckPerson(Person person)
{
    return person.Cars.Any() || person.Children.Any(x => CheckPerson(x) != null) ? person : null;                    
}

但我认为你应该归还IEnumerable<Person>,其中包含所有有车的人(或一个孩子有车)。

也许是这样的:

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;
         }
    }
}