列表与LT;>迭代性能

时间:2014-10-15 10:26:19

标签: c# list iteration

嗨,我对迭代值列表的效率有疑问。

我想知道你必须查看一个值列表,提取符合当前搜索条件的值,删除找到的匹配项是否有意义,从而产生较小的列表在下一次迭代中搜索的值。或者这没什么区别。这是我的代码。

foreach (Project prj in projectList)
        {
            string prjCode = prj.Code;

            var match = usersProjects.FirstOrDefault(x => x.Code == prjCode);
            if (match != null)
            {
                usersProjects.Remove(match);
                //More logic here
            }
        }

基本上我正在搜索与所有项目列表中的用户相对应的项目代码。 假设有50个项目,用户可以访问其中的20个。是否每次循环删除找到的项目都会减少整个项目的数量,从而使迭代更有效率?谢谢。

3 个答案:

答案 0 :(得分:3)

我不建议更改列表 - 它本身很慢,命令为O(n)。

使用准备好的查找来执行您想要的操作,而不是FirstOrDefault()

var projectLookup = usersProjects.ToLookup((x) => x.Code);

foreach (Project prj in projectList)
    {
        string prjCode = prj.Code;

        var match = projectLookup[prjCode].FirstOrDefault()

        if (match != null)
        {
            //More logic here
        }
    }

请注意,ToLookup()代价很高,因此您希望尽可能保留查找 - 请考虑仅在userProjects更改时重新创建查找。之后,实际使用查找来检索匹配只需要恒定的时间。

答案 1 :(得分:1)

我建议使用群组加入:

var matches =
    from prj in projectList
    join x in usersProjects on prj.Code equals x.Code into xs
    where xs.Any()
    select xs.First();

实际上,稍微好一点的查询是:

var matches =
    from prj in projectList
    join x in usersProjects on prj.Code equals x.Code into xs
    from x1 in xs.Take(1)
    select x1;

如果您需要从usersProjects列表中删除它们,则需要执行此操作:

foreach (var match in matches)
{   
    usersProjects.Remove(match);
}

但是,如果你只是想知道usersProjects 中剩下的内容你删除了匹配项,那么你可以这样做:

var remainingUsersProjects = usersProjects.Except(matches);

在所有这一切结束时,您唯一需要做的就是时间所有选项,以便了解更快的内容。

但我认为除非你的名单很庞大,否则这无关紧要。否则,我会选择最简单的代码,以便将来维护您的项目。

答案 2 :(得分:0)

您可以使用简单的FirstOrDefault()方法来获取所有用户项目,而不是循环和多个Where()调用:

userProjects = userProjects.Where(up => projectList.All(p => up.Code != p.Code))