使用 linq 实现密集秩

Posted

技术标签:

【中文标题】使用 linq 实现密集秩【英文标题】:implement dense rank with linq 【发布时间】:2016-11-20 05:48:58 【问题描述】:

使用以下 linq 代码,如何将 dense_rank 添加到我的结果中?如果这太慢或太复杂,那么只使用排名窗口函数怎么样?

var x = tableQueryable
    .Where(where condition)
    .GroupBy(cust=> new  fieldOne = cust.fieldOne ?? string.Empty, fieldTwo = cust.fieldTwo ?? string.Empty)
    .Where(g=>g.Count()>1)
    .ToList()
    .SelectMany(g => g.Select(cust => new 
        cust.fieldOne
    ,   cust.fieldTwo
    ,   cust.fieldThree
    ));

【问题讨论】:

您的 GroupBy 方法没有意义。你不应该指定一个 Func 来提取密钥吗? dense_rank 是什么? @TimothyGhanem 你能解释一下吗?我遵循与codeducky.org/sql-queries-in-linq/#group-by相同的语法 @user3185569 dense_rank() 是一个 sql 窗口函数 - msdn.microsoft.com/en-us/library/ms173825.aspx @TimothyGhanem 是的,这是我的要求的一部分,你知道如何实现dense_rank 函数吗? 【参考方案1】:

这是一个dense_rank()。根据您的需要更改GroupByOrder :) 基本上,dense_rank 对查询的有序组进行编号,因此:

var DenseRanked = data.Where(item => item.Field2 == 1)
    //Grouping the data by the wanted key
    .GroupBy(item => new  item.Field1, item.Field3, item.Field4 )
    .Where(@group => @group.Any())

    // Now that I have the groups I decide how to arrange the order of the groups
    .OrderBy(@group => @group.Key.Field1 ?? string.Empty)
    .ThenBy(@group => @group.Key.Field3 ?? string.Empty)
    .ThenBy(@group => @group.Key.Field4 ?? string.Empty)

    // Because linq to entities does not support the following select overloads I'll cast it to an IEnumerable - notice that any data that i don't want was already filtered out before
    .AsEnumerable()

    // Using this overload of the select I have an index input parameter. Because my scope of work is the groups then it is the ranking of the group. The index starts from 0 so I do the ++ first.
    .Select((@group , i) => new
    
       Items = @group,
       Rank = ++i
    )

    // I'm seeking the individual items and not the groups so I use select many to retrieve them. This overload gives me both the item and the groups - so I can get the Rank field created above
    .SelectMany(v => v.Items, (s, i) => new
    
       Item = i,
       DenseRank = s.Rank
    ).ToList();

另一种方法是 Manoj 在 this question 中的回答所指定的 - 但我不喜欢它,因为从表中选择了两次。

【讨论】:

@MikeTurner - 编辑为拥有更多您的字段。您不需要在末尾添加AsQuerable,然后您应该在Wheres 的所有过滤器之后拥有AsEnumerable()。这个例子应该有效。如果没有,请尝试首先列出您班级的虚拟项目,看看它是否符合您需要的逻辑。只有到最后才真正从数据库中获取数据并查看 @GiladGreen 这个代码看起来不错。您能否添加一些 cmets 来帮助理解您的逻辑? @Mike - 你可以玩它 - 这些函数中的每一个都有一个匿名函数 - 所以在这里它们是一个内衬,但对于每个你都可以打开一个范围并做任何你想做的事情:) 但是我认为如果您在此查询中添加更多逻辑以确定您的键/顺序,那么最好将此逻辑专门用于合适的类。将保持代码更简洁、更可测试和更可扩展 @MikeTurner - 要使 linq 到实体 order by 工作,您需要按照我上面写的方式使用它。这是a question 专门针对这一点的。现在,如果您想执行此操作,请使用更通用的 dense_rank 函数,该函数将包含这些 group byorder by see this @MikeTurner - 这是一种很好的方法,但我更希望有一个具有特定实现的接口,然后运行上述代码的类将获取接口作为依赖项并使用它要正确执行。 See Dependency Injection - 这是一个更高级的概念,所以我将从扩展开始,然后尝试执行此操作。 Linq.Dynamic 也可以,但我还没有使用太多 :)【参考方案2】:

所以,如果我理解正确的话,密集排名是对组进行排序时的组索引。

var query = db.SomeTable
    .GroupBy(x => new  x.Your, x.Key )
    .OrderBy(g => g.Key.Your).ThenBy(g => g.Key.Key)
    .AsEnumerable()
    .Select((g, i) => new  g, i )
    .SelectMany(x =>
        x.g.Select(y => new
        
            y.Your,
            y.Columns,
            y.And,
            y.Key,
            DenseRank = x.i,
        
    );

【讨论】:

以上是关于使用 linq 实现密集秩的主要内容,如果未能解决你的问题,请参考以下文章

对记录进行排序后使用密集排名

R语言编写自定义函数使用Wilcoxon符号秩检验(Wilcoxon signed rank)实现多分组非参数成对检验(pairwise)并使用p.adjust函数调整概率值

基于matlab的低秩结构重构算法仿真实现,对比ALM,IT,APG,ADMM

数据结构与算法分析 - 3 - 向量

数据结构与算法分析 - 3 - 向量

并查集的两种实现(按秩合并+路径压缩)