2

我正在努力解决这个问题,而不仅仅是将其归结为一般的巫毒教。

我做一个 EF 查询并取回一些数据,我.ToList()就是这样:

IEnumerable<DatabaseMatch<CatName>> nameMatches = nameLogicMatcher.Match(myIQueryableOfCats).ToList();

有些猫在数据库中出现两次,因为它们有多个名称,但每只猫都有一个主名称。因此,为了过滤掉这个,我在一个列表中获取了所有猫的 ID:

List<int> catIds = nameMatches.Select(c => c.Match.CatId).ToList();

然后,我遍历所有不同的 id,获取所有匹配的猫名,并从列表中删除任何不是主要名称的内容,如下所示:

foreach (int catId in catIds.Distinct())
{
    var allCatNameMatches = nameMatches.Where(c => c.Match.CatId == catId);

    var primaryMatch = allCatNameMatches.FirstOrDefault(c => c.Match.NameType == "Primary Name");

    nameMatches = nameMatches.Except(allCatNameMatches.Where(c => c != primaryMatch)); 
}

现在这段代码,当我第一次运行它时,就挂了。我认为这很奇怪。我穿过它,它似乎可以工作,但经过 10 次迭代(总共限制为 100 只猫)它开始减速,然后最终它变成了冰川,然后完全挂起。

我认为它可能错误地进行了一些密集的数据库工作,但是分析器显示没有执行任何 SQL,除了检索猫名的初始列表。

我决定将它从IEnumerablenameMatches 更改为 a List,并将适当.ToList()的放在最后一行。在我这样做之后,它立即完美地工作了。

我想问的问题是,为什么?

4

2 回答 2

3

如果没有s,您将在等待延迟执行的嵌套链ToList()中构建。这可能不是那么糟糕,除非您还调用将执行链的每个迭代。因此,在迭代次数n上,您正在执行循环n-1中包含的过滤操作。如果您有 1000 只不同的猫,则 Linq 链将执行1000 + 99 + ... + 1次。(我认为你有O(n³)的东西!)nameMatchesIEnumerableFirstOrDefault

道理是,如果你想使用延迟执行,请确保你只执行一次你的链。

于 2013-10-16T10:26:09.013 回答
0

让我们稍微简化一下您的代码:

foreach (int catId in catIds.Distinct())
{
    var allCatNameMatches = nameMatches.Where(c => c.Match.CatId == catId);
    var primaryMatch = null;
    nameMatches = nameMatches.Except(allCatNameMatches.Where(c => c != primaryMatch)); 
}

还有一点:

foreach (int catId in catIds.Distinct())
{
    nameMatches = nameMatches.Where(c => c.Match.CatId == catId);
    var primaryMatch = null;
    nameMatches = nameMatches.Except(nameMatches.Where(c => c != primaryMatch)); 
}

在后一种情况下,很明显,由于延迟执行,foreachbody 的每一次传递都会延长Whereand的链Except。然后记住var primaryMatch = allCatNameMatches.FirstOrDefault。它不是延迟执行的,因此在它的每次迭代中foreach都应该执行所有链。因此它挂起。

于 2013-10-16T10:25:05.030 回答