Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# linq nested "conditional/composite" grouping

Tags:

c#

linq

grouping

I need some help writing a LINQ query where I am trying to do some "conditional/composite" grouping. (Not sure that is the right term). Let me explain.

If I have the following classes:

class Device
{
    int Id;
    string DeviceType;
    string DeeviceValue;
}

class Employee
{
    int Id;
    int SupervisorId;
    int CountryId;
    List<Device> Devices = new List<Device>();
}

From this lets say I have these Objects:

List<Employee> Employees = new List<Employee>();
var emp1 = new Employee();
emp1.Id = 1;
emp1.CountryId = 1;
emp1.SupervisorId = 1;
Device dev1 = new Device();
dev1.Id = 1;
dev1.DeviceType = "Desk Phone";
dev1.DeviceValue = "132456789";
emp1.Devices.Add(dev1);
Employees.Add(emp1);

var emp2 = new Employee();
emp2.Id = 2;
emp2.CountryId = 1;
emp2.SupervisorId = 1;
Device dev2 = new Device();
dev2.Id = 2;
dev2.DeviceType = "Desk Phone";
dev2.DeviceValue = "123456789";
emp2.Devices.Add(dev2);
Device dev6 = new Device();
dev6.Id = 6;
dev6.DeviceType = "Conference Phone";
dev6.DeviceValue = "123456789";
emp2.Devices.Add(dev6);
Employees.Add(emp2);

var emp3 = new Employee();
emp3.Id = 3;
emp3.CountryId = 2;
emp3.SupervisorId = 1;
Device dev3 = new Device();
dev3.Id = 3;
dev3.DeviceType = "Desk Phone";
dev3.DeviceValue = "456789123";
emp3.Devices.Add(dev3);
Employees.Add(emp3);

var emp4 = new Employee();
emp4.Id = 4;
emp4.CountryId = 2;
emp4.SupervisorId = 4;
Device dev4 = new Device();
dev4.Id = 4;
dev4.DeviceType = "Desk Phone";
dev4.DeviceValue = "987123456";
emp4.Devices.Add(dev4);
Device dev5 = new Device();
dev5.Id = 5;
dev5.DeviceType = "Dealerboard";
dev5.DeviceValue = "987123456";
emp4.Devices.Add(dev5);
Employees.Add(emp4);

From this I want to create a query that groups by -> SupervisorId -> CountryId -> DeviceType. Which is fine and I have the below query which gives me what I want.

var result = Employees.SelectMany(e => e.Devices, (employee, devices) => new { employee, devices })
.GroupBy(e => new { e.devices.DeviceType, e.employee.SupervisorId, e.employee.CountryId })
.Select(e => new
    {
        DeviceType = e.Key.DeviceType,
        Supervisor = e.Key.SupervisorId,
        Country = e.Key.CountryId,
        employees = e
    });

The problem I have is that I want to create one DeviceType group that can include multiple device types, "Desk Phone" and "Conference Phone", rather than having an individual group for each device type.

EDIT - For completeness

The above query gives me the following result

  1. Device Type -> Desk Phone
    • SupervisorId -> 1
    • CountryId -> 1
    • Employees -> This will be employees with Id = 1 and Id = 2
  2. Device Type -> Conference Phone
    • SupervisorId -> 1
    • CountryId -> 1
    • Employees -> This will be employee with Id = 2
  3. Device Type -> Desk Phone
    • SupervisorId -> 1
    • CountryId -> 2
    • Employees -> This will be employee with Id = 3
  4. Device Type -> Desk Phone
    • SupervisorId -> 4
    • CountryId -> 2
    • Employees -> This will be employee with Id = 4
  5. Device Type -> Dealerboard
    • SupervisorId -> 4
    • CountryId -> 2
    • Employees -> This will be employee with Id = 4

The result I am after is:

  1. Device Type -> Desk Phone & Conference Phone
    • SupervisorId -> 1
    • CountryId -> 1
    • Employees -> This will be employees with Id = 1 and Id = 2
  2. Device Type -> Desk Phone
    • SupervisorId -> 1
    • CountryId -> 2
    • Employees -> This will be employee with Id = 3
  3. Device Type -> Desk Phone
    • SupervisorId -> 4
    • CountryId -> 2
    • Employees -> This will be employee with Id = 4
  4. Device Type -> Dealerboard
    • SupervisorId -> 4
    • CountryId -> 2
    • Employees -> This will be employee with Id = 4

Is there a way to do this via LINQ and modifiying the query I already have?

Any help would be much appreciated.

Pete

like image 577
Pete Avatar asked Oct 30 '22 19:10

Pete


1 Answers

Create a dictionary with key for each device type and value for their group, then use the dictionary on grouping

var deviceGroup = new Dictionary<string, string>() { { "Desk Phone", "Phone" }, { "Conference Phone", "Phone" } };

var result = Employees.SelectMany(e => e.Devices, (employee, devices) => new { employee, devices })
            .GroupBy(e => new { 
DeviceGroup = deviceGroup.ContainsKey(e.devices.DeviceType) ? 
              deviceGroup[e.devices.DeviceType] 
              : e.devices.DeviceType, 
e.employee.SupervisorId, e.employee.CountryId })
.Select(e => new
{
DeviceGroup = e.Key.DeviceGroup,

Supervisor = e.Key.SupervisorId,
Country = e.Key.CountryId,
employees = e
});
like image 174
Martheen Avatar answered Nov 12 '22 22:11

Martheen