【问题标题】:Recursion with the least sideeffect副作用最小的递归
【发布时间】:2015-09-02 09:39:11
【问题描述】:

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

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

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

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

我尝试的其他方法如下。

  • 返回无效
  • 返回布尔值
  • 参考参数

我也尝试在没有返回值的情况下执行此操作,只是回头查看输入人员的结果,但这并没有保存更改。

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

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

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

【问题讨论】:

  • 孩子的孩子有车怎么办?你把所有的父母都养了吗?还是只是第一级?
  • 从树叶开始工作,一找到车就包括树枝。
  • @Thomas 我想从树根(所以是最年长的祖父母)导航到所有有车的人。所以我需要中间的每一步来保持树结构的活力

标签: c# recursion side-effects


【解决方案1】:

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

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

但我认为您应该返回一个 IEnumerable&lt;Person&gt;,其中包含所有有车的人(或一个孩子有车)。

也许是这样的:

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

【讨论】:

  • ???不,但是 ?: 运算符将返回它....Any().Count() &gt; 0 完全相同,但不会遍历所有项目以获得实际计数。它只测试是否有一个项目。
  • 在下面的例子中,树形结构不会消失吗?我尝试了最上面的例子,它运行良好,但我不确定它是如何工作的。没车的孩子为什么要搬走?(想要这个但不太明白)
  • 是的,你会失去树状结构。第二个示例遍历所有项目并返回子树中所有有汽车的项目。您将获得所有项目的平面“列表”而不是树,但在大多数情况下,您将为每个符合您的条件的项目执行操作。在这种情况下,您不需要知道如何遍历树。您将在一个简单的 Enumerable 中使所有项目变得懒惰。如果您更喜欢第一个或第二个示例,这取决于您的需求。
猜你喜欢
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 2020-07-03
相关资源
最近更新 更多