Linq分组和嵌套分组
Linq grouping and nested grouping
我正在创建一个可以用各种分组显示的 TreeView
。基本 类 如下:
public class MachineStatus
{
public string MachineName {get;set;}
public string Department {get;set;}
public string LocationName {get;set;}
public IEnumerable<DeviceStatus> Devices {get;set;}
}
public class DeviceStatus
{
public string DeviceName {get;set;}
public string DeviceType {get;set;}
public string IpAddress {get;set;}
public ConnectionStatus Status {get;set;}
}
小组将由 Department
、Location
和 DeviceType
组成。前两个使用 Linq 很容易。然而,DeviceType
具有挑战性,因为每个 Machine
可能包含多个 Device
个不同类型的对象。
原始数据
Machine 1
|__ Device A (Type Foo)
|__ Device B (Type Bar)
Machine 2
|__ Device C (Type Foo)
|__ Device D (Type Zed)
结果
Type Bar
|__ Machine 1
|__Device B
Type Foo
|__Machine 1
|__Device A
|__Machine 2
|__Device C
Type Zed
|__Machine 2
|__Device D
我想我必须在尝试分组之前展平 MachineStatus
记录的列表,但我在使用 SelectMany 时感到困惑...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestConsoleApp
{
class Program
{
static void Main(string[] args) {
DeviceStatus deviceA = new DeviceStatus() { DeviceName = "A", DeviceType = "foo" };
DeviceStatus deviceB = new DeviceStatus() { DeviceName = "B", DeviceType = "bar" };
DeviceStatus deviceC = new DeviceStatus() { DeviceName = "C", DeviceType = "foo" };
DeviceStatus deviceD = new DeviceStatus() { DeviceName = "D", DeviceType = "zed" };
MachineStatus status1 = new MachineStatus() { MachineName = "1", Department = "1", LocationName = "1", Devices = new List<DeviceStatus>{ deviceA, deviceB} };
MachineStatus status2 = new MachineStatus() { MachineName = "2", Department = "2", LocationName = "2", Devices = new List<DeviceStatus> { deviceC, deviceD } };
List<MachineStatus> machines = new List<MachineStatus>() { status1, status2};
var result = machines.SelectMany(x => x.Devices, (a, b) => new { DeviceType = b.DeviceType, MachineName = a.MachineName, DeviceName = b.DeviceName } );
var result2 = result.GroupBy(x => new {x.DeviceType}).Select( z => new { DeviceType = z.Key.DeviceType, Machines = z.ToList().GroupBy(y => y.MachineName) });
foreach (var group1 in result2)
{
foreach (var group2 in group1.Machines)
{
foreach (var group3 in group2)
{
Console.Write(group1.DeviceType + ":");
Console.Write(group3.MachineName + ":");
Console.WriteLine(group3.DeviceName);
}
}
}
Console.ReadLine();
}
public class MachineStatus
{
public string MachineName { get; set; }
public string Department { get; set; }
public string LocationName { get; set; }
public IEnumerable<DeviceStatus> Devices { get; set; }
}
public class DeviceStatus
{
public string DeviceName { get; set; }
public string DeviceType { get; set; }
public string IpAddress { get; set; }
public ConnectionStatus Status { get; set; }
}
public class ConnectionStatus
{
}
}
}
产生了以下输出:
foo:1:A
foo:2:C
bar:1:B
zed:2:D
分组为:
foo:1:A
foo:2:C
bar:1:B
zed:2:D
您可以像这样使用 SelectMany & GroupBy 实现此目的:-
var result = machines.SelectMany(x => x.Devices,
(machineObj, devices) => new { machineObj, devices })
.GroupBy(x => new { x.devices.DeviceType, x.machineObj.Department,
x.machineObj.LocationName })
.Select(x => new
{
DeviceType = x.Key.DeviceType,
Department = x.Key.Department,
Location = x.Key.LocationName,
machines = x
});
这是完整的 Working Fiddle,其中包含我使用的示例数据,下面是相同的输出。
我正在创建一个可以用各种分组显示的 TreeView
。基本 类 如下:
public class MachineStatus
{
public string MachineName {get;set;}
public string Department {get;set;}
public string LocationName {get;set;}
public IEnumerable<DeviceStatus> Devices {get;set;}
}
public class DeviceStatus
{
public string DeviceName {get;set;}
public string DeviceType {get;set;}
public string IpAddress {get;set;}
public ConnectionStatus Status {get;set;}
}
小组将由 Department
、Location
和 DeviceType
组成。前两个使用 Linq 很容易。然而,DeviceType
具有挑战性,因为每个 Machine
可能包含多个 Device
个不同类型的对象。
原始数据
Machine 1
|__ Device A (Type Foo)
|__ Device B (Type Bar)
Machine 2
|__ Device C (Type Foo)
|__ Device D (Type Zed)
结果
Type Bar
|__ Machine 1
|__Device B
Type Foo
|__Machine 1
|__Device A
|__Machine 2
|__Device C
Type Zed
|__Machine 2
|__Device D
我想我必须在尝试分组之前展平 MachineStatus
记录的列表,但我在使用 SelectMany 时感到困惑...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestConsoleApp
{
class Program
{
static void Main(string[] args) {
DeviceStatus deviceA = new DeviceStatus() { DeviceName = "A", DeviceType = "foo" };
DeviceStatus deviceB = new DeviceStatus() { DeviceName = "B", DeviceType = "bar" };
DeviceStatus deviceC = new DeviceStatus() { DeviceName = "C", DeviceType = "foo" };
DeviceStatus deviceD = new DeviceStatus() { DeviceName = "D", DeviceType = "zed" };
MachineStatus status1 = new MachineStatus() { MachineName = "1", Department = "1", LocationName = "1", Devices = new List<DeviceStatus>{ deviceA, deviceB} };
MachineStatus status2 = new MachineStatus() { MachineName = "2", Department = "2", LocationName = "2", Devices = new List<DeviceStatus> { deviceC, deviceD } };
List<MachineStatus> machines = new List<MachineStatus>() { status1, status2};
var result = machines.SelectMany(x => x.Devices, (a, b) => new { DeviceType = b.DeviceType, MachineName = a.MachineName, DeviceName = b.DeviceName } );
var result2 = result.GroupBy(x => new {x.DeviceType}).Select( z => new { DeviceType = z.Key.DeviceType, Machines = z.ToList().GroupBy(y => y.MachineName) });
foreach (var group1 in result2)
{
foreach (var group2 in group1.Machines)
{
foreach (var group3 in group2)
{
Console.Write(group1.DeviceType + ":");
Console.Write(group3.MachineName + ":");
Console.WriteLine(group3.DeviceName);
}
}
}
Console.ReadLine();
}
public class MachineStatus
{
public string MachineName { get; set; }
public string Department { get; set; }
public string LocationName { get; set; }
public IEnumerable<DeviceStatus> Devices { get; set; }
}
public class DeviceStatus
{
public string DeviceName { get; set; }
public string DeviceType { get; set; }
public string IpAddress { get; set; }
public ConnectionStatus Status { get; set; }
}
public class ConnectionStatus
{
}
}
}
产生了以下输出:
foo:1:A
foo:2:C
bar:1:B
zed:2:D
分组为:
foo:1:A
foo:2:C
bar:1:B
zed:2:D
您可以像这样使用 SelectMany & GroupBy 实现此目的:-
var result = machines.SelectMany(x => x.Devices,
(machineObj, devices) => new { machineObj, devices })
.GroupBy(x => new { x.devices.DeviceType, x.machineObj.Department,
x.machineObj.LocationName })
.Select(x => new
{
DeviceType = x.Key.DeviceType,
Department = x.Key.Department,
Location = x.Key.LocationName,
machines = x
});
这是完整的 Working Fiddle,其中包含我使用的示例数据,下面是相同的输出。