首页 > 解决方案 > Two order bys then picking the last element in linq

问题描述

A for fun problem. I normally prefer to think about enumerables using linq statements, but in this case I'm not wrapping my head around it as well. Based on what I've read I might be needing a call to ThenBy? Below is an example of what the proper foreach implementation looks like:

var groupByRepository = flattenedBuilds.GroupBy(x => x.Repository);
foreach (var repositoryBuilds in groupByRepository)
{
    var groupByBranch = repositoryBuilds.GroupBy(x => x.SourceBranch);
    foreach (var branchBuild in groupByBranch)
    {
        var versionsOrdered = branchBuild.OrderBy(x => x.Version);
        var firstVersion = versionsOrdered.LastOrDefault();
        yield return firstVersion;
    }
}

Basically it groups on repository then by branch so that I can see the latest build version for each.

Even though I don't like the SQL like version of linq that seems to be the best way to express this. This version though is missing the important LastOrDefault() call.

So the question is what would this linq (or some other linq) need to make this equivalent. A goal is readability, but in looking at my current link versus the foreach loop I'm pretty sure the foreach is winning there.

var result = from build in flattenedBuilds
             group build by build.Repository into groupByRepository
             from repositories in groupByRepository
             group repositories by repositories.SourceBranch into groupBySourceBranch
             from sourceBranches in groupBySourceBranch
             orderby sourceBranches.Version
             select sourceBranches;
return result;

标签: c#linq

解决方案


我会做这样的事情。我试图推断你的扁平数据的结构,虽然我不完全确定我读对了......但我认为你flattenedBuilds是这个类所代表的项目列表:

class FlattenedBuild
{
    public string Branch { get; set; }
    public string Repository { get; set; }
    public int Version { get; set; }
}

所以我写了这个来构建一些示例数据(就像List我的例子一样)

static FlattenedBuild B(string repo, string branch, int version)
{
    return new FlattenedBuild 
    { 
       Branch = branch, 
       Repository = repo, 
       Version = version 
    };
}

...

var flattenedBuilds = new List<FlattenedBuild>()
{
   B("Project X", "master",1),
   B("Project X", "master",2),
   B("Project X", "master",3),
   B("Project X", "develop",2),
   B("Project X", "develop",8),
   B("Project Y", "master",1),
   B("Project Y", "feature_main",1),
   B("Project Y", "develop",4),
   B("Project Y", "develop",6),
   B("Project Y", "develop",12)
};

然后实际的 LINQ 内容只是按存储库和分支的所有唯一组合进行分组,然后获得最高的构建号。对于每个独特的组合:

var result = flattenedBuilds
    .GroupBy(b => new { b.Repository, b.Branch })
    .Select(g => new
    {
       g.Key.Repository,
       g.Key.Branch,
       LastBuild = g.OrderByDescending(v => v.Version).FirstOrDefault()?.Version
    });

然后简单地检查结果:

 foreach (var x in result)
 {
    Console.WriteLine($"last build for {x.Repository}/{x.Branch} was {x.LastBuild}");
 }

输出这个:

last build for Project X/master was 3
last build for Project X/develop was 8
last build for Project Y/master was 1
last build for Project Y/feature_main was 1
last build for Project Y/develop was 12

认为这是你所追求的?


推荐阅读