Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a list and all its nested objects using LINQ

There is an organisation with several departments and each department has a few employees.

I have created the following object model:

public class Organisation
{
    public int Code { get; set; }
    public string Type { get; set; }
    public string Name { get; set; }
    public List<Department> Departments { get; set; }
}

public class Department
{
    public int Code { get; set; }
    public string Name { get; set; }
    public List<Employee> Employees { get; set; }
}

public class Employee
{
    public int Code { get; set; }
    public string Name { get; set; }
}

Now, I have a list of these organisations and using LINQ, I would like to sort/order the output as follows:

1) Organisations: Ordered by Code and Name

2) Departments: Ordered by Code and Name

3) Employees: Ordered by Code and Name

Below is some test data that I have populated:

var britishTelecomLtd = new Organisation
            {
                Code = 8,
                Name = "British Telecom Ltd",
                Type = "Institutional",
                Departments =  new List<Department>
                    {
                        new Department
                            {
                                Code = 6,
                                Name = "Finance",
                                Employees = new List<Employee>
                                    {
                                        new Employee
                                            {
                                                Code = 5,
                                                Name = "Peter"
                                            },
                                            new Employee
                                            {
                                                Code = 2,
                                                Name = "James"
                                            },
                                            new Employee
                                            {
                                                Code = 6,
                                                Name = "Andrew"
                                            }
                                    }
                            },
                            new Department
                            {
                                Code = 5,
                                Name = "Accounts",
                                Employees = new List<Employee>
                                    {
                                        new Employee
                                            {
                                                Code = 15,
                                                Name = "Jane"
                                            },
                                            new Employee
                                            {
                                                Code = 22,
                                                Name = "John"
                                            },
                                            new Employee
                                            {
                                                Code = 16,
                                                Name = "Mark"
                                            }
                                    }
                            }

                    } 

            };

        var virginMediaLtd = new Organisation
        {
            Code = 5,
            Name = "Virgin Media Ltd",
            Type = "Institutional",
            Departments = new List<Department>
                    {
                        new Department
                            {
                                Code = 6,
                                Name = "Sales",
                                Employees = new List<Employee>
                                    {
                                       new Employee
                                            {
                                                Code = 5,
                                                Name = "Peter"
                                            },
                                            new Employee
                                            {
                                                Code = 2,
                                                Name = "James"
                                            },
                                            new Employee
                                            {
                                                Code = 6,
                                                Name = "Andrew"
                                            }
                                    }
                            },
                            new Department
                            {
                                Code = 5,
                                Name = "Support",
                                Employees = new List<Employee>
                                    {
                                        new Employee
                                            {
                                                Code = 15,
                                                Name = "Jane"
                                            },
                                            new Employee
                                            {
                                                Code = 22,
                                                Name = "John"
                                            },
                                            new Employee
                                            {
                                                Code = 16,
                                                Name = "Mark"
                                            }
                                    }
                            }

                    }

        };

        var pcWorldLtd = new Organisation
        {
            Code = 18,
            Name = "PC World Ltd",
            Type = "Retail",
            Departments = new List<Department>
                    {
                        new Department
                            {
                                Code = 6,
                                Name = "Marketing",
                                Employees = new List<Employee>
                                    {
                                          new Employee
                                            {
                                                Code = 15,
                                                Name = "Jane"
                                            },
                                            new Employee
                                            {
                                                Code = 22,
                                                Name = "John"
                                            },
                                            new Employee
                                            {
                                                Code = 16,
                                                Name = "Mark"
                                            }
                                    }
                            },
                            new Department
                            {
                                Code = 5,
                                Name = "Customer Services",
                                Employees = new List<Employee>
                                    {
                                         new Employee
                                            {
                                                Code = 5,
                                                Name = "Kelly"
                                            },
                                            new Employee
                                            {
                                                Code = 2,
                                                Name = "Jenny"
                                            },
                                            new Employee
                                            {
                                                Code = 6,
                                                Name = "Tricia"
                                            }
                                    }
                            }

                    }

        };

        var blueCatLtd = new Organisation
            {
                Code = 3,
                Name = "Blue Cat Music Ltd",
                Type = "Retail",
                Departments = new List<Department>
                    {
                        new Department
                            {
                                Code = 6,
                                Name = "Sales",
                                Employees = new List<Employee>
                                    {
                                         new Employee
                                            {
                                                Code = 5,
                                                Name = "Peter"
                                            },
                                            new Employee
                                            {
                                                Code = 2,
                                                Name = "James"
                                            },
                                            new Employee
                                            {
                                                Code = 6,
                                                Name = "Andrew"
                                            }
                                    }
                            },
                        new Department
                            {
                                Code = 5,
                                Name = "Warehouse",
                                Employees = new List<Employee>
                                    {
                                        new Employee
                                            {
                                                Code = 5,
                                                Name = "Andy"
                                            },
                                        new Employee
                                            {
                                                Code = 2,
                                                Name = "Robert"
                                            },
                                        new Employee
                                            {
                                                Code = 6,
                                                Name = "Dave"
                                            }
                                    }
                            }

                    }
            };

        var organisations = new List<Organisation>
            {
                britishTelecomLtd,
                virginMediaLtd,
                pcWorldLtd,
                blueCatLtd
            };

Here I am adding the data to a dictionary:

   var legalEntitiesCollectionByType = new Dictionary<string, ICollection<Organisation>>
            {
                {
                    "Institutional", organisations
                        .Where(x => x.Type == "Institutional")
                        .OrderBy(x => x.Code).ThenBy(x => x.Name)
                        .ToList()
                },
                {
                    "Retail", organisations
                        .Where(x => x.Type == "Retail")
                        .OrderBy(x => x.Code).ThenBy(x => x.Name)
                        .ToList()
                }
            };

doing it this way the sorting only happens at the Organisation level and not on the department or the employee level.

My question is, how can I achieve sorting on all 3 levels within the object hierarchy while populating the dictionary above?

Cheers

like image 302
haroonxml Avatar asked Sep 17 '13 15:09

haroonxml


People also ask

What sort does LINQ use?

LINQ includes five sorting operators: OrderBy, OrderByDescending, ThenBy, ThenByDescending and Reverse. LINQ query syntax does not support OrderByDescending, ThenBy, ThenByDescending and Reverse. It only supports 'Order By' clause with 'ascending' and 'descending' sorting direction.

How would you sort the list in ascending order LINQ?

In LINQ, the OrderBy operator is used to sort the list/ collection values in ascending order. In LINQ, if we use order by the operator by default, it will sort the list of values in ascending order. We don't need to add any ascending condition in the query statement.

What is nested list in C#?

A nested list is a list that appears as an element in another list. In this list, the element with index 3 is a nested list. If we print( nested[3] ), we get [10, 20] . To extract an element from the nested list, we can proceed in two steps. First, extract the nested list, then extract the item of interest.


2 Answers

You can sort before :

    organisations.ToList().ForEach(o => o.Departments = o.Departments.OrderBy(d => d.Code).ToList());
    organisations.SelectMany(o => o.Departments).ToList().ForEach(d => d.Employees = d.Employees.OrderBy(e => e.Name).ToList());

And then use the list already sorted

        var legalEntitiesCollectionByType = new Dictionary<string, ICollection<Organisation>>
        {
            {
                "Institutional", organisations
                    .Where(x => x.Type == "Institutional")
                    .ToList()
            },
            {
                "Retail", organisations
                    .Where(x => x.Type == "Retail")
                    .ToList()
            }
        };

NB : the sort is not in place, you can achieve this using a comparer

        organisations.ToList().ForEach(o => o.Departments.Sort(CreateCustomComparison));
        organisations.SelectMany(o => o.Departments).ToList().ForEach(d => d.Employees.Sort(CreateCustomComparison));
like image 96
Toto Avatar answered Sep 28 '22 01:09

Toto


If Employees ever need to be sorted by code and name then you can make that property a SortedList<>.

public class Department
{
    ...
    public SortedList<Tuple<int, string>, Employee> Employees { get; set; }
}

Prior to .NET 4 you could use KeyValuePair instead of Tuple.

When creating Employees object you'd need to provide IComparer object for sorted list's key.

Employees = new SortedList<Tuple<int, string>, Employee>(new EmployeeKeyComparer());

where EmployeeKeyComparer could be defined as

public class EmployeeKeyComparer : IComparer<Tuple<int, string>>
{
    public int Compare(Tuple<int, string> x, Tuple<int, string> y)
    {
        if (x.First == y.First)
            return StringComparer.Ordinal.Compare(x.Second, y.Second);
        else
            return x.First.CompareTo(y.First);
    }
}
like image 41
Dialecticus Avatar answered Sep 28 '22 00:09

Dialecticus