【问题标题】:LINQ JOIN performance optimizationLINQ JOIN 性能优化
【发布时间】:2021-12-06 03:06:26
【问题描述】:

我目前正在开发一个 .NET Core 3.1 应用程序。

我需要使用 LINQ 过滤列表并尽可能优化性能。

我当前的代码运行良好,但我想知道性能。

目标

  • SearchResult 的结果需要过滤
  • 必须只有一个不同的 Id
  • 有时我得到两个具有相同 Id 的项目,即 1,然后我需要删除一个项目
  • 但是:如果有多个项目具有相同的 Id 值,即 1,那么我需要删除没有 ContactId 的项目。如果两个项目都没有 ContactId,我可以选择第一个匹配项。
  • 最终结果需要先按Id排序,再按ContactId排序
public class SearchResult
{
    public int? Id {get; set;}
    public int? ContactId {get; set;}
}

public class Program
{
    public static void Main()
    {
        var searchResults = new List<SearchResult>
        {
            new SearchResult { Id = 1 },
            new SearchResult { Id = 2 }, // yes
            new SearchResult { Id = 3 }, // yes
            new SearchResult { Id = 4 }, // yes
            new SearchResult { Id = 5 },
            
            new SearchResult { Id = 1, ContactId = 1 }, // yes
            new SearchResult { Id = 5, ContactId = 3 }, // yes
            
            new SearchResult { Id = 1, ContactId = 1 },
            new SearchResult { Id = 8, ContactId = 4 }, // yes
            
            new SearchResult { Id = 1 }, 
            new SearchResult { Id = 2 }, 
            new SearchResult { Id = 10 }, // yes
            new SearchResult { Id = 11 }, // yes
            new SearchResult { Id = 12 }, // yes
        };
        
        // group1 without contactId
        var group1 = searchResults
                        .Where(sr => sr.ContactId == null)
                        .GroupBy(sr => sr.Id)
                        .Select(grp => grp.First());
        
        // group2 WITH contactId
        var group2 = searchResults
                        .Where(sr => sr.ContactId != null)
                        .GroupBy(sr => sr.Id)
                        .Select(grp => grp.First());
        
        // joined = group1.Id - group2.Id
        var joined = group1.Where(g1 => !group2.Any(g2 => g2.Id == g1.Id));
        
        // result = group2 + joined
        var merged = new List<SearchResult>();
        merged.AddRange(group2);
        merged.AddRange(joined);
        
        // result ordered by id then by contactId
        var result = merged
            .OrderBy(x => x.Id)
            .ThenBy(x => x.ContactId);
        
        foreach(var sr in result){         
            Console.WriteLine(sr.Id + " " + sr.ContactId);
        }       
    }
}

到目前为止一切顺利 - 我的代码“有效”,但也许有人知道如何改进此代码及其性能?

【问题讨论】:

  • 可能有几千个条目,取决于:) ..我从 OData 查询中得到结果。

标签: c# linq asp.net-core


【解决方案1】:

更简单的解决方案是先对数据进行排序,然后根据 id 对其进行分组。这应该比加入数据更高效。

    var searchResults = new List<SearchResult>
    {
        new SearchResult { Id = 1 },
        new SearchResult { Id = 2 }, // yes
        new SearchResult { Id = 3 }, // yes
        new SearchResult { Id = 4 }, // yes
        new SearchResult { Id = 5 },
        
        new SearchResult { Id = 1, ContactId = 1 }, // yes
        new SearchResult { Id = 5, ContactId = 3 }, // yes
        
        new SearchResult { Id = 1, ContactId = 1 },
        new SearchResult { Id = 8, ContactId = 4 }, // yes
        
        new SearchResult { Id = 1 }, 
        new SearchResult { Id = 2 }, 
        new SearchResult { Id = 10 }, // yes
        new SearchResult { Id = 11 }, // yes
        new SearchResult { Id = 12 }, // yes
    };
    
    var result = searchResults
                 .OrderBy(x => x.Id)
                 .ThenByDescending(x => x.ContactId)
                 .GroupBy(p => p.Id)
                 .Select(x => x.First());
    
    foreach(var sr in result){         
        Console.WriteLine(sr.Id + " " + sr.ContactId);
    }  

【讨论】:

  • 谢谢,这个解决方案效果很好!
【解决方案2】:

您只需要这个简单高效的查询:

List<SearchResult> resultList = searchResults
    .GroupBy(s => s.Id)
    .OrderBy(sg => sg.Key)
    .Select(sg => sg.OrderBy(s => s.ContactId != null ? 0 : 1).ThenBy(s => s.ContactId).First())
    .ToList();

GroupBy之后排序,减少排序的必要性。

【讨论】:

  • 谢谢,这个解决方案效果很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多