首页 > 解决方案 > 使用 groubBy 的 LINQ 过滤器查询

问题描述

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

我需要按以下要求过滤 LINQ 查询:

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 { },
            new SearchResult { Id = 2 }, // yes
            new SearchResult { Id = 3 }, // yes
            new SearchResult { Id = 4 }, // yes
            new SearchResult { Id = 5 },
                        
            new SearchResult { Id = 5, ContactId = 3 }, // yes
            new SearchResult { Id = 1, ContactId = 1 }, // yes
            new SearchResult { Id = 1, ContactId = 5 }, // yes
            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
        };
        
        // unfortunately this LINQ query does not work correctly:
        var result = searchResults
                 .OrderBy(x => x.Id)
                 .ThenBy(x => x.ContactId)
                 .GroupBy(p => new { p.Id, p.ContactId })
                 .Select(x => x.First());
        
        foreach(var sr in result){         
            Console.WriteLine(sr.Id + " " + sr.ContactId);
        }       
    }

预期的结果应该是:

1 1
1 5
2 
3 
4  
5 3
8 4
10 
11 
12 

不幸的是,我的 LINQ 查询无法正常工作。

你知道如何解决这个问题并根据规则过滤 LINQ 查询吗?

标签: c#.netlinq

解决方案


我建议这样的事情。下面我们GroupBy分析一下各个组。最后,我们将 s变平 groupIEnumerable<SearchResult>(please, fiddle )

为了删除重复项,我们应该知道如何比较项目是否相等,然后调用Distinct. 我们可以为此实现 IEqualityComparer:

private class MyEqualityComparer : IEqualityComparer<SearchResult> {
  public bool Equals(SearchResult x, SearchResult y) {
    if (ReferenceEquals(x, y))
      return true;
    else if (null == x || null == y)
      return false;

    return x.Id == y.Id && x.ContactId == y.ContactId;
  }

  public int GetHashCode(SearchResult obj) => (obj != null && obj.Id.HasValue)
    ? obj.Id.Value
    : 0; 
}

最终代码:

  var result = searchResults
    .Where(item => item.ContactId.HasValue || item.Id.HasValue)
    .Distinct(new MyEqualityComparer()) // remove duplicates
    .GroupBy(item => item.Id)
    .Select(group => group.Any(item => item.ContactId.HasValue)
       ? group.Where(item => item.ContactId.HasValue)
       : group.Take(1))
    .SelectMany(group => group); 

我们来看一下:

 Console.WriteLine(string.Join(Environment.NewLine, result
   .Select(item => $"{item.Id} {item.ContactId}")));

结果:

1 1
1 5
2 
3 
4 
5 3
8 4
10 
11 
12 

推荐阅读