StackoverflowException递归和执行缓慢 - c#

我有这个代码

private static void Count(List<DataRowSet> rows, int id, ref int count)
{
    foreach (DataRowSet row in rows) {
        if (row.parentId == id) {
            count++;

            Count(rows, row.Id, ref count);
        }
    }
}

和这个班

public class DataRowSet
{
    public int Id;
    public int parentId;

    public DataRowSet(int id, int parent)
    {
        this.Id = id;
        this.parentId = parent;
    }
}

我想计算具有特定ID的List<DataRowSet>的每个孩子。

Count(dataList, 1, ref cnt);

那行得通,但是一旦我在dataList中有8000多个条目,就会发生StackOverflow异常。代码也很慢,大约需要1.5秒才能找到所有条目。

我该如何解决?

参考方案

StackOverflowException发生是因为您的递归太深了。它可以正常工作到8000,上面的所有内容对于堆栈来说实在太多了。
您可以通过使用Stack<DataRowSet>并将项目推入其中来解决此问题,而不是递归调用该函数。

查看您的DataRowSet类似乎是一个简单列表,因此有一种简单的方法可以通过使用ILookup<int, DataRowSet>来提高性能。这样,您可以使用键查找任何相关项,而不必一次又一次地遍历列表。

首先,您必须将顶级项目压入堆栈。可以这样完成。

Stack<DataRowSet> stack = new Stack<DataRowSet>(
    dataRows.Where(x => x.Id == id));

使用dataRows.ToLookup,可以按条目的ParentId对其分组。

ILookup<int, DataRowSet> dataLookup = dataRows.ToLookup(x => x.parentId);

之后,您只需要遍历stack直到其为空,同时推送具有正确ID的新项目。

while (stack.Count > 0) {
    DataRowSet currentRow = stack.Pop();

    foreach (DataRowSet rowSet in dataLookup[currentRow.Id]) {
        stack.Push(rowSet);
    }
}

这样,您就不必再担心StackOverflowException了,并且性能也得到了提高。

总体而言,您的新功能将看起来像这样。

private static int Count(List<DataRowSet> dataRows, int id)
{
    int totalDescendants = 0;

    Stack<DataRowSet> stack = new Stack<DataRowSet>(
        dataRows.Where(x => x.Id == id));

    ILookup<int, DataRowSet> dataLookup = dataRows.ToLookup(x => x.parentId);

    while (stack.Count > 0) {
        DataRowSet currentRow = stack.Pop();

        foreach (DataRowSet rowSet in dataLookup[currentRow.Id]) {
            totalDescendants++;
            stack.Push(rowSet);
        }
    }

    return totalDescendants;

}

可以这样称呼

int cnt = Count(dataList, 1);

C#Linq可空INT字段包含在List <int>中SQL转换 - c#

我有一张表格,其中列出了需要管理员签名的表单,而我想要做的就是将表单列表过滤到他们可以签名的表单。我得到了他们所管理的员工列表,然后将其放入员工ID列表中。var staffIds = manager.Staff.Select(x => x.Id).ToList(); 然后,我使用人员列表过滤表单列表。我得到了所有与经过身份验证的组织ID相匹配的表单,…

在PHP中使用long int - php

我正在尝试此方法,但无法存储较大的价值$var = rand(100000000000000,999999999999999); echo $var; // prints a 9 digit value(largest possible) 如何获得期望值? 参考方案 PHP整数通常为32位。其他软件包提供了更高精度的整数:http://php.net/man…

使用jquery计算<id>中的总图像 - php

我有一个div,里面有一些图像,例如<img src= etc我想计算该div中的图像总数。我也想使用PHP将这些图像ID保存到mysql中...谢谢 参考方案 要计算它们,您可以执行以下操作:alert($('#myDiv img').length); 要将所有id捕获到数组中,可以执行以下操作:var ids = []; $(&…

剃刀付款集成->如何通过关闭按钮X检测剃刀付款模型是否关闭 - javascript

当用户关闭而无需付款时,我在CI框架中使用Razorpay,请创建razor支付模型,然后取消订单,我希望按状态更改为已取消的状态触发查询。所以我怎么能检测到这一点。我已经通过单击jQuery单击关闭功能但无法使用... javascript大神给出的解决方案 Razorpay提供了JS方法来检测模式关闭。您编写的任何JS代码都不会在结帐页面上运行,因为它是…

如何使用箭头符号(->)创建受保护的方法? - java

当我们编写以下代码时Stream.of(1,2,3,4,5).filter(i -> (i%2 == 0)).map( i -> i*i ); 表达式i -> (i%2 == 0)或i -> i*i将变为私有方法。在我的用例中,编写了一个junit测试,以确保没有方法是私有的(是的,这是强制性的),并且对于这些lambda表达式而言,…