List<>上的递归循环导致stackoverflow

时间:2010-08-20 20:53:17

标签: c# .net list recursion stack-overflow

我有List<>个包含两个字符串和一个DateTime的对象。我想构建另一个相同对象的列表,其中只包含最后一个唯一项,使用两个字符串作为键和最后一个DateTime值。在SQL中考虑以下内容:

SELECT col1, col2, MAX(datetime) FROM table GROUP BY col1, col2

这给出了col1,col2和最后一个日期时间的唯一列表。所以..我试图在两个列表的代码中这样做。其中一个包含重复内容,它只解析并抓取其中的最后一个唯一项目以填充第二个列表。

我拥有的数据集非常庞大,所以只需通过重复列表然后检查项目是否在唯一列表中,如果它没有添加它,如果是,则比较日期等等。这很慢。所以我认为我可以递归地遍历重复列表并抓住唯一的项目找到他们的最大日期时间并在我循环时删除非最大值,使我的重复列表变得越来越小,从而加快了速度。 (我希望你还跟着我......)

无论如何。我写了一个带有两个列表的递归循环,但是当我遍历时,我会在第3000次迭代时获得System.StackOverflowException

这是我的代码。想象一下,ListWithDuplicates充满了数据。实际ListDataItem有更多属性我遗漏了。但我的主要问题是为什么我不能以这种方式遍历public list而不会导致StackOverflowException

using System;
using System.Net;
using System.IO;
using System.Collections.Generic;
using System.Linq;

public class RecursionTest
{
    public List<listDataItem> ListWithDuplicates { get; set; }
    public List<listDataItem> ListWithUniques { get; set; }

    public RecursionTest()
    {
        Process();
    }

    public void Process()
    {
        int rowcount = 0;
        int duplicates = 0;
        int total = 0;
        RecursiveLoopForUnique(ref rowcount, ref duplicates, ref total, "", "");
    }

    private void RecursiveLoopForUnique(ref int rowcount, ref int duplicates, ref int total, string col1, string col2)
    {
        if (rowcount > 0)
            duplicates += ListWithDuplicates.RemoveAll(z => z.COL1 == col1 && z.COL2 == col2);
        if (ListWithDuplicates.Count > 0)
        {
            foreach (listDataItem item in ListWithDuplicates)
            {
                rowcount++;
                if (ListWithUniques.FindAll(z => z.COL1 == item.COL1 && z.COL2 == item.COL2).Count < 1)
                {
                    ListWithUniques.Add(ListWithDuplicates.FindAll(z => z.COL1 == item.COL1 && z.COL2 == item.COL2).OrderByDescending(z => z.DATETIME).First());
                    col1 = item.COL1;
                    col2 = item.COL2;
                    break;
                }
            }
            RecursiveLoopForUnique(ref rowcount, ref duplicates, ref total, col1, col2);
        }
        else
            return;
    }

    public class listDataItem
    {
        public string COL1 { get; set; }
        public string COL2 { get; set; }
        public DateTime DATETIME { get; set; }            

        public listDataItem(string col1, string col2, DateTime datetime)
        {
            COL1 = col1;
            COL2 = col2;
            DATETIME = datetime;
        }
    }
}

5 个答案:

答案 0 :(得分:2)

LINQ,是的。

listDataItem latestListDataItem =
    ListWithDuplicates.Where(item => item.COL1 == yourCol1Param && item.COL2 == yourCol2Param)
                      .Max(item => item.DATETIME);

MSDN注意到..

其中:http://msdn.microsoft.com/en-us/library/bb534803.aspx

Max:http://msdn.microsoft.com/en-us/library/bb347632.aspx

OrderBy:http://msdn.microsoft.com/en-us/library/bb534966.aspx

上次:http://msdn.microsoft.com/en-us/library/bb358775.aspx

答案 1 :(得分:2)

这个怎么样:

Dictionary<string, item> destDict = new Dictionary<string, item>();

foreach (item curr in items)
{
    string key = curr.col1 + curr.col2;
    if (!destDict.Keys.Contains(key))
    {
        destDict.Add(key, curr);
    }
    else
    {
        if (destDict[key].date < curr.date)
        {
            destDict[key].date = curr.date;
        }
    }
}

我在包含2个独特的col1 / col2对的1000个列表中进行了测试。工作得很好,比LINQ groupby / select更快。

答案 2 :(得分:0)

我不确定语法,但它应该很接近。

from d in DupsList
group d.DATETIME on d.col1, d.col2 in grp
select new listDataItem  (grp.Key.col1, grp.Key.col2, grp.Max()};

答案 3 :(得分:0)

好吧,如果你有超过几千个独特的C1,C2对,那么你会遇到这个,因为你为每个独特的群体重复一次。

有很多方法可以解决这个问题;一个会更清晰,更快速的方法是按C1和C2对列表进行排序,然后将其下移一次以找到每个组中的最新日期。如果你没有坚持自己重新实现它,最好的方法是:

ListWithUniques = ListWithDuplicates
    .GroupBy(x => new { COL1, COL2 })
    .Select(g => g.OrderByDescending(x => x.DATETIME).First())

答案 4 :(得分:0)

SELECT col1, col2, MAX(datetime) FROM table GROUP BY col1, col2
LINQ中的

var query = from row in table
            group row into g
            select new
            {
                Col1 = g.Key.Col1,
                Col2 = g.Key.Col2,
                Date = g.Max(b => b.Date)
            };

以一种可能更有用的形式:

var dict = query.ToDictionary(a => new { a.Col1, a.Col2 }, a => a.Date);

然后你可以像这样引用它:

DateTime specificMaxDate = dict[new { Col1 = 2, Col2 = 3 }];
相关问题