2015-03-11 2 views
2

Я нахожусь в создании TreeView, который может отображаться с различными группировками. Основные классы ниже:Linq группировка и вложенная группировка

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 ...

+0

Вы получаете шанс посмотреть на мой ответ? .. –

+1

Да, я сделал, я в процессе интеграции. Я хотел изучить несколько вещей, прежде чем отметить это как ответ (на самом деле просто добавить комментарии для будущих людей, которым это может понадобиться). Интеграция анонимных типов в древовидное представление ... не весело :) Я обновлю сегодня. – Killnine

+0

Из ваших данных результата представляется, что вы группируете устройства по имени машины, а также типа - так что двухуровневая вложенная группировка. Это правильно? – Enigmativity

ответ

1

Вы можете добиться этого с помощью 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 с данными выборки я использовал и следующие является выходом для таких же.

enter image description here

1
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:
Foo: 2: C
бар: 1: B
ZED: 2: D

Который сгруппированных как:

Foo: 1:
Foo: 2: С

бар: 1: B

зет: 2: D

+0

Примечание: вывод состоит из 4 записей, сгруппированных в исходном вопросе. Это точный ожидаемый результат (не 5) –