在C#中使用Linq比较两个集合

5

我想在C#中比较两个集合,目前我正在使用嵌套的"for"循环来实现。是否有使用Linq进行相同操作的更快且更有效的方法?这是我当前的代码,它可以完美地工作,只是想要一种更高效的方法:

OrgCollection myYears = Org.RetrieveDistinctYear();
if (myYears.Count > 0)
{
AcademicYearCollection allYears = AcademicYear.RetrieveAll();
for (int i = 0; i < myYears.Count; i++)
{
    for (int j = 0; j < allYears.Count; j++)
    {
        if (myYears[i].AcademicYearCode == allYears[j].Code)
        {
        ddlYear.Items.Insert(0, new ListItem(allYears[j].Name,allYears[j].Code));
        break;
        }
    }
}
}

我希望将AcademicYearCollection中的"Code"与OrgCollection中的"AcademicYearCode"属性进行比较,如果相同,则将其添加到下拉列表"ddlYear"中。
谢谢您的提前帮助。

将它们排序并在一个循环中进行比较。 - nhahtdh
尝试访问此链接:https://dev59.com/qU7Sa4cB1Zd3GeqP5J8n?rq=1未来的结论是,在发布任何问题之前进行一些研究。 - Harry89pl
你预计从 RetrieveDistinctYear 函数中会返回多少个项目? - Jodrell
随着时间的推移,数据量已经很大的东西。 - DAK
那么,我回答中的字典方法可能会更快,你需要测试一下才能确定。 - Jodrell
4个回答

15

你可以在LINQ中完成这个操作,这将使代码更加简洁。要知道它是否更有效率,你需要对其进行分析。我认为LINQ的join操作符在内部使用了某种哈希桶,这应该会提供更好的性能,特别是在集合很大的情况下。你当前的解决方案是O(N ^ 2),如果选项数量增加,它将很快降级。

OrgCollection myYears = Org.RetrieveDistinctYear();
AcademicYearCollection allYears = AcademicYear.RetrieveAll();

var items = from y in myYears
            join ay in allYears
            on y.Code equals ay.AcademicYearCode
            select new { ay.Name, ay.Code }

1
Anders回应已删除的评论,实际上你可以使用Intersect,只要传递自己的IEqualityComparer即可。但这样做更好 :) - Filip Ekberg
只需要第一个匹配项,无需交集。 - Jodrell
这个表达式将计算所有匹配项,但问题只要求第一个。后续处理是浪费的努力。 - Jodrell
@Jodrell:你说得对,我没有看到原问题中的break,所以如果有多个匹配项,这确实会返回一个单独的结果。然而,如果只有一个匹配项,它将是相同的,但非O(N^2)(如果我正确理解了linq的join)。 - Anders Abel
Jon Skeet 在这里指出 http://stackoverflow.com/questions/271615/better-performance-on-updating-objects-with-linq,`Join` 内部会生成一个 Lookup ,因此我认为 Join 从哈希中受益。 - Jodrell

0
OrgCollection myYears = Org.RetrieveDistinctYear();
if (myYears.Count > 0)
{
    AcademicYearCollection allYears = AcademicYear.RetrieveAll();
    for (int i = 0; i < myYears.Count; i++)
    {
         if (allYears[j].Any(allY => allY ==  myYears[i].AcademicYearCode ))
            {
                ddlYear.Items.Insert(0, new ListItem(allYears[j].Name, allYears[j].Code));
                break;
            }

    }
}

这可能是一个选项,但我认为扩展方法“any”通过迭代方式实现了相同的功能。


0

这个怎么样?

var allYears = AcademicYear.RetrieveAll().ToDictionary(y => y.Code, y.Name);

ListItem match = null;
foreach(var year in Org.RetrieveDistinctYear())
{
    if (allYears.HasKey(year.AcademicYearCode)
    {
        match = new ListItem(
                       allYears[year.AcademicYearCode], 
                       year.AcademicYearCode);
        break;
    }
}

if (match != null)
{
    ddlYear.Items.Insert(0, match); 
}

在这里使用字典可以提供卓越的性能,而且结果更接近 Org.RetrieveDistinctYear 的匹配效果越好,获益也就越大。如果RetrieveDistinctYear的结果经常很短或者匹配在顶部,那么创建字典的开销将使代码变得不必要地慢。

编辑

或者尝试这种方法

var allYears = AcademicYear.RetrieveAll().ToDictionary(y => y.Code, y.Name);

var matchingCode = Org.RetrieveDistinctYear()
    .Select(y = y.AcademicYearCode)
    .FirstOrDefault(code => allYears.HasKey(code));

if (!string.IsEmptyOrWhitespace(matchingCode))
{
    ddlYear.Items.Insert(0, new ListItem(
                                 allYears[matchingCode], 
                                 matchingCode)); 
}

0

这个解决方案与您原来的解决方案具有相似的速度和效率,但是可以通过将 from y in myYears 更改为 from y in myYears.AsParallel() 来并行化,以可能加快速度。

OrgCollection myYears = Org.RetrieveDistinctYear();
AcademicYearCollection allYears = AcademicYear.RetrieveAll();

var items = from y in myYears
            let match = allYears.FirstOrDefault( ay => y.AcademicYearCode == ay.Code)
            where match != null
            select new ListItem(match.Name, match.Code);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接