我有一个Column
课程,如下所示:
public class Column
{
public int LocId { get; set; }
public int SecId { get; set; }
public double StartElevation { get; set; }
public double EndElevation { get; set; }
}
Column
个对象列表:
List<Column> Columns = new List<Column>();
例如:
Columns:
{
Column1: { LocId = 1 , SecId = 1, StartElevation = 0, EndElevation = 160 }
Column2: { LocId = 1 , SecId = 1, StartElevation = 160, EndElevation = 320 }
Column3: { LocId = 1 , SecId = 2, StartElevation = 320, EndElevation = 640 }
Column4: { LocId = 2 , SecId = 1, StartElevation = 0, EndElevation = 160 }
Column5: { LocId = 2 , SecId = 2, StartElevation = 160, EndElevation = 320 }
}
我想使用 Linq 将以下算法应用于上面的列表。
浏览Columns
列表并:
(A)选择具有相同LocId
的项目列表。
(B)然后从该列表中选择另一个具有相同SecId
的项目列表。
这将给我一个列表,希望我能在其上执行其他任务。
因此,将上述算法应用于上述数据将是这样的。
Columns List
---------------------------------------------------------
| Column1 Column2 Column3 Column4 Column5 |
---------------------------------------------------------
|
|
(A)
|
|
--------------------------------------------
| |
GroupBasedOnLocId GroupBasedOnLocId
| |
----------- -----------
| Column1 | | Column4 |
| Column2 | | Column5 |
| Column3 | -----------
----------- |
| |
(B) (B)
| |
------------------------- -------------------------
| | | |
| | | |
GroupBasedOnSecId GroupBasedOnSecId GroupBasedOnSecId GroupBasedOnSecId
| | | |
| | | |
Column1 Column3 Column4 Column5
Column2
如何使用LINQ完成此操作?
答案 0 :(得分:6)
将.GroupBy
与复合键一起使用。
示例代码:
List<Column> Columns = new List<Column>
{
new Column { LocId = 1 , SecId = 1, StartElevation = 0, EndElevation = 160 },
new Column { LocId = 1 , SecId = 1, StartElevation = 160, EndElevation = 320 },
new Column { LocId = 1 , SecId = 2, StartElevation = 320, EndElevation = 640 },
new Column { LocId = 2 , SecId = 1, StartElevation = 0, EndElevation = 160 },
new Column { LocId = 2 , SecId = 2, StartElevation = 160, EndElevation = 320 }
};
foreach (var group in Columns.GroupBy(c => new { c.LocId, c.SecId }))
{
Console.WriteLine("group: LocId = {0}, SecId = {1}", group.Key.LocId, group.Key.SecId);
foreach(Column column in group)
Console.WriteLine(" item: StartElevation = {0}, EndElevation = {1}", column.StartElevation, column.EndElevation);
}
您可以按照自己的方式转换群组:
foreach (var res in Columns.GroupBy(c => new { c.LocId, c.SecId })
.Select(g => new
{
g.Key.LocId,
g.Key.SecId,
MinStartElevation = g.Min(c => c.StartElevation),
MaxEndElevation = g.Max(c => c.EndElevation)
}))
{
Console.WriteLine("LocId = {0}, SecId = {1}, MinStartElevation = {2}, MaxEndElevation = {3}",
res.LocId, res.SecId, res.MinStartElevation, res.MinStartElevation);
}
答案 1 :(得分:4)
如果您想要图表所示的两级分组,则需要使用GroupBy
两次:
var grouping = columns
.GroupBy(col => new { col.LocId, col.SecId }) // create groups by LocId+SecId
.GroupBy(group => group.Key.LocId); // re-group by LocId only
然后,您将拥有一系列群组,每个群组都有一个int
密钥(即LocId
)并且由一系列其他群组组成,每个群组一个具有LocId
和SecId
的复合键,并且由一系列列组成(匹配LocId
和SecId
)。
然后,您可以通过foreach
访问每个级别的两级分组。例如:
foreach (var locGroup in grouping) {
Console.WriteLine("LocId: " + locGroup.Key)
foreach (var secGroup in locGroup) {
Console.WriteLine(" SecId:" + secGroup.Key.SecId)
Console.WriteLine(" Min StartElevation: {0}",
secGroup.Min(col => col.StartElevation);
Console.WriteLine(" Max EndElevation: {0}",
secGroup.Max(col => col.EndElevation);
foreach (var column in secGroup) {
Console.WriteLine(" {0} -> {1}", column.StartElevation, column.EndElevation);
}
}
}
}
或者,如果您希望能够在树中找到特定节点,可以使用ToDictionary
和ToLookup
:
var lookup = columns
// group columns by LocId
.GroupBy(col => col.LocId)
// create a dictionary from the groups to find them by LocId,
// where the value of each entry is a lookup of its own columns by SecId
.ToDictionary(
locGroup => locGroup.Key,
locGroup => locGroup.ToLookup(col => col.SecId));
然后你可以做以下事情:
var locId = "123";
var locGroup = lookup[locId];
Console.WriteLine("LocId {0} has {1} sub-groups", locId, locGroup.Count);
Console.WriteLine("LocId {0} has {1} total columns", locId,
locGroup.Sum(secGroup => secGroup.Count()));
var secId = "456";
var secGroup = locGroup[secId];
Console.WriteLine("LocId {0}, SecId {1} has {2} columns",
locId, secId, secGroup.Count());
答案 2 :(得分:2)
这是一个使用 LINQ查询语法的解决方案。 (查询语法和方法语法在语义上相同,but many people find query syntax simpler and easier to read.)
// Declare and then populate the LINQ source.
List<Column> columns = new List<Column>();
var query =
from column in columns
group column by new {column.LocId, column.SecId} into g
orderby g.Key.LocId, g.Key.SecId
select new
{
LocId = g.Key.LocId,
SecId = g.Key.SecId,
Columns = g
};
下面您将使用您提供的数据找到此LINQ查询的完整演示程序。我已经在演示程序之前使用了预期的输出。另请参阅live demo。
预期输出
LocId:1, SecId:1
StartElevation:0, EndElevation:160
StartElevation:160, EndElevation:320
LocId:1, SecId:2
StartElevation:320, EndElevation:640
LocId:2, SecId:1
StartElevation:0, EndElevation:160
LocId:2, SecId:2
StartElevation:160, EndElevation:320
<强>程序强>
using System;
using System.Collections.Generic;
using System.Linq;
class LinqGroupDemo
{
static public void Main(string[] args)
{
var query =
from column in GetSource()
group column by new {column.LocId, column.SecId} into g
orderby g.Key.LocId, g.Key.SecId
select new
{
LocId = g.Key.LocId,
SecId = g.Key.SecId,
Columns = g
};
foreach (var key in query)
{
Console.WriteLine("LocId:{0}, SecId:{1}",
key.LocId,
key.SecId);
foreach (var column in key.Columns)
{
Console.WriteLine(" StartElevation:{0}, EndElevation:{1}",
column.StartElevation,
column.EndElevation);
}
}
}
static private List<Column> GetSource()
{
return new List<Column>
{
new Column { LocId = 1 , SecId = 1, StartElevation = 0, EndElevation = 160 },
new Column { LocId = 1 , SecId = 1, StartElevation = 160, EndElevation = 320 },
new Column { LocId = 1 , SecId = 2, StartElevation = 320, EndElevation = 640 },
new Column { LocId = 2 , SecId = 1, StartElevation = 0, EndElevation = 160 },
new Column { LocId = 2 , SecId = 2, StartElevation = 160, EndElevation = 320 }
};
}
}
public class Column
{
public int LocId { get; set; }
public int SecId { get; set; }
public double StartElevation { get; set; }
public double EndElevation { get; set; }
}
答案 3 :(得分:1)
使用GroupBy
:
var results = columns
.GroupBy(column => column.LocId)
.Select(group => group.GroupBy(c => c.Sec.Id));