使用 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 方法没有意义。你不应该指定一个 Funcdense_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()
。根据您的需要更改GroupBy
和Order
:)
基本上,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
,然后您应该在Where
s 的所有过滤器之后拥有AsEnumerable()
。这个例子应该有效。如果没有,请尝试首先列出您班级的虚拟项目,看看它是否符合您需要的逻辑。只有到最后才真正从数据库中获取数据并查看
@GiladGreen 这个代码看起来不错。您能否添加一些 cmets 来帮助理解您的逻辑?
@Mike - 你可以玩它 - 这些函数中的每一个都有一个匿名函数 - 所以在这里它们是一个内衬,但对于每个你都可以打开一个范围并做任何你想做的事情:) 但是我认为如果您在此查询中添加更多逻辑以确定您的键/顺序,那么最好将此逻辑专门用于合适的类。将保持代码更简洁、更可测试和更可扩展
@MikeTurner - 要使 linq 到实体 order by
工作,您需要按照我上面写的方式使用它。这是a question 专门针对这一点的。现在,如果您想执行此操作,请使用更通用的 dense_rank
函数,该函数将包含这些 group by
和 order 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函数调整概率值