【问题标题】:Linq to compare two collections in C#Linq 在 C# 中比较两个集合
【发布时间】:2012-07-05 12:42:17
【问题描述】:

我想比较两个我目前正在使用嵌套“for”循环的 C# 集合。在 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 中的“代码”与 OrgCollection 中的“AcademicYearCode”属性进行比较,如果相同,则将其添加到下拉列表“ddlYear”中。

提前致谢。

【问题讨论】:

  • 排序并循环比较。
  • 试试link 未来的结论。在发布任何问题之前进行一些研究
  • 您预计RetrieveDistinctYear会提供多少项目
  • 随着时间的推移会增加并且已经有很多数据的东西。
  • 那么我的答案中的字典方法可能会更快,您必须测试才能看到。

标签: c# linq


【解决方案1】:

您可以在 LINQ 中执行此操作,它可以提供更短的代码。要知道它是否更有效,您必须对其进行分析。我认为 linq 的连接运算符在内部使用某种哈希桶,这应该可以提供更好的性能,尤其是在集合很大的情况下。您当前的解决方案是 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 }

【讨论】:

  • Anders 响应被删除的评论,如果你通过自己的 IEqualityComparer,你实际上可以使用Intersect。但这更好:)
  • 除了,你不需要相交,只需要第一个匹配
  • 此表达式将计算所有匹配项,但问题只要求第一个。后续处理是白费力气。
  • @Jodrell:你说得对,我在原始问题中没有看到break,所以如果有多个匹配项,这确实会返回一个单独的结果。如果只有一个匹配项,那么它将是相同的,但不是 O(N^2) (如果我正确理解了 linq 的连接)。
  • 或没有匹配项 :-),Jon Skeet 在此声明 stackoverflow.com/questions/271615/… Join 在内部生成 Lookup,因此我同意 Join 将从散列中受益。
【解决方案2】:
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;
            }

    }
}

这可能是一个选项,但我认为扩展方法“任何”通过迭代以相同的方式工作。

【讨论】:

    【解决方案3】:

    这个怎么样

    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); 
    }
    

    在此处使用Dictionary 可提供卓越的性能,并且匹配的 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)); 
    }
    

    【讨论】:

      【解决方案4】:

      此解决方案与您的原始解决方案具有相似的速度和效率,但可以通过将 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);
      

      【讨论】:

        猜你喜欢
        • 2014-12-10
        • 1970-01-01
        • 2012-03-22
        • 2012-05-05
        • 1970-01-01
        • 1970-01-01
        • 2020-08-06
        • 2020-04-17
        相关资源
        最近更新 更多