带组的复杂 LINQ 排序
我试图根据以下(简化的)规则对项目列表进行排序:
我将每个项目都具有以下属性:
Id (int),
ParentId (int?),
Name (string)
ParentID 是一个到 Id 的自连接外键。如果一个项目有 ParentId,那么父项目也将存在于列表中。
我需要对列表进行排序,以便所有具有父级的项目都立即出现在其父级之后。然后所有项目将按名称排序。
因此,如果我有以下内容:
Id: 1, ParentId: null, Name: Pi
Id: 2, ParentId: null, Name: Gamma
Id: 11, ParentId: 1, Name: Charlie
Id: 12, ParentId: 1, Name: Beta
Id: 21, ParentId: 2, Name: Alpha
Id: 22, ParentId: 2, Name: Omega
那么我希望它们按如下方式排序:
ID:2、21、22、1、12、11
目前我能想到的最好办法是先按名称排序,然后按 ParentId 分组,如下所示:
var sortedItems = itemsToSort.OrderBy(x=> x.Name).GroupBy(x=> x.ParentId);
我的起始计划如下:(在非功能状态代码)
var finalCollection = new List<Item>
var parentGroup = sortedItems.Where(si => si.Key == null);
foreach(parent in parentGroup)
{
finalCollection.Add(parent);
foreach(child in sortedItems.Where(si => si.Key == parent.Id)
{
finalCollection.Add(child);
}
}
但是,parentGroup 不是
IEnumerable<Item>
,所以这不起作用。
我觉得有一种更简单、更简洁的方法可以实现这一目标,但目前它却让我困惑——任何人都可以帮忙吗?
I am trying to sort a list of items according to the following (simplified) rules:
I'll each item has the following properties:
Id (int),
ParentId (int?),
Name (string)
ParentID is a self-join ForeignKey to Id. If an item has a ParentId, then the parent will also exist in the list.
I need to sort the list so that all items which have a parent, appear immediately after their parent. Then all items will be sorted by Name.
So if I had the following:
Id: 1, ParentId: null, Name: Pi
Id: 2, ParentId: null, Name: Gamma
Id: 11, ParentId: 1, Name: Charlie
Id: 12, ParentId: 1, Name: Beta
Id: 21, ParentId: 2, Name: Alpha
Id: 22, ParentId: 2, Name: Omega
Then I would want them sorted as follows:
Ids: 2, 21, 22, 1, 12, 11
At the moment the best I can come up with is to sort by Name first, and then Group by ParentId as follows:
var sortedItems = itemsToSort.OrderBy(x=> x.Name).GroupBy(x=> x.ParentId);
My starting plan was then as follows: (in non functioning code)
var finalCollection = new List<Item>
var parentGroup = sortedItems.Where(si => si.Key == null);
foreach(parent in parentGroup)
{
finalCollection.Add(parent);
foreach(child in sortedItems.Where(si => si.Key == parent.Id)
{
finalCollection.Add(child);
}
}
However, parentGroup is not
IEnumerable<Item>
so this does not work.
I feel there is an simpler, more concise way of achieving this, but currently it's eluding me - can anyone help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您只有两个级别,您可以这样做:
最初,项目按名称排序,确保稍后将它们分成组时它们保持排序。
然后创建一个查找表,允许通过
ParentId
进行查找。然后,使用SelectMany
将通过null ParentId
标识的父级与其子级连接起来,并使用查找表来查找子级。将父级插入到子级之前以获得所需的序列。如果你想解决两层以上的一般情况,你需要使用递归。这是一种递归获取节点子树的方法:
代码几乎与上面的简单情况相同:
通过使用递归 lambda,您甚至可以“内联”完成所有操作:
If you only have two levels you can do it like this:
Intially items are sorted by name ensuring that when they are later split into groups they stay sorted.
Then a lookup table is created allowing to lookup by
ParentId
. The parents identified by having anull ParentId
are then joined with their children usingSelectMany
and the lookup table is used to find the children. The parent is inserted before the children to get the desired sequence.If you want to solve the general case with more than two levels you need to employ recursion. Here is a way to recursively get the substree for a node:
The code is almost the same as the simpler case above:
By using a recursive lambda you can even do it all "inline":
据我了解您的问题,您希望按父名称(如果是父名称)然后按子名称(如果是子名称)对结果进行排序,但您希望所有子名称都出现在列表中各自的父名称之后。
这应该可以解决问题:
更新以解决
@Martin Liversage
提到的问题。这是输出:
As I understand your question you want to order the results by parent name (if it's a parent) and then by child name (if it's a child), but you want all children to appear in the list after their respective parent.
This should do the trick:
Updated to address the issue that
@Martin Liversage
mentioned.Here's the output:
这可以通过以下方式实现:
实例:http://rextester.com/rundotnet?code=WMEZ40628
输出为:
This can be achieved using:
Live example: http://rextester.com/rundotnet?code=WMEZ40628
Output is:
我会选择 DoctaJonez 的 答案 2 级。
它可以扩展到 n 层,如下所示:
I'd go with DoctaJonez's answer for 2 level.
It can be extended to n levels like so:
这
将使
parentGroup
IEnumerable
。你会在顶层失去懒惰,但我认为由于上下文,这很好。
This
will make
parentGroup
IEnumerable<Item>
.You will loose laziness on the top level, but i think it's fine due to the context.
这个怎么样?
然后要获取排序列表,请执行以下操作:
简单。 :-)
How about this?
And then to get the sorted list do this:
Simple. :-)