两个命令bys然后在linq中选择最后一个元素

时间:2019-06-13 18:53:35

标签: c# linq

一个有趣的问题。我通常更喜欢使用linq语句来考虑可枚举,但是在这种情况下,我也不会全神贯注。根据我阅读的内容,我可能需要致电ThenBy?下面是正确的foreach实现的示例:

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

基本上,它在存储库上分组,然后按分支分组,以便我可以看到每个版本的最新构建版本。

即使我不喜欢linq的类似SQL的版本,这似乎也是表达这一点的最佳方法。但是,此版本缺少重要的LastOrDefault()调用。

所以问题是此linq(或其他linq)需要做些什么来使其等效。一个目标是可读性,但是在查看我当前的链接与foreach循环时,我很确定foreach在那里赢了。

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;

2 个答案:

答案 0 :(得分:0)

我会做这样的事情。尽管我不确定我已经完全正确地阅读了该文本,但我已经尝试推断出您拼合数据的结构...但是我认为您的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

我想 是什么?

答案 1 :(得分:0)

foreach代码进行或多或少的直接翻译会产生:

var ans = flattenedBuilds.GroupBy(b => b.Repository)
                         .SelectMany(b_rg => b_rg.GroupBy(b => b.SourceBranch)
                                                 .Select(b_r_sbg => b_r_sbg.OrderByDescending(x => x.Version).First())
                         );

OrderByDescending / First相比,我更喜欢OrderBy / Last,因为First立即返回,效率更高。另外,GroupBy将仅创建包含至少一个成员的组,因此不需要FirstOrDefault-您知道至少有一个成员。