10

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

haroonxml
  • 356
  • 1
  • 3
  • 14
  • 4
    You sort when you query your dictionary, not when you populate it. – Mister Epic Sep 17 '13 at 15:18
  • 2
    If it must happen in this method, then you need to recreate each object and sort the elements while doing this. For example: `.OrderBy(x => x.Code).ThenBy(x => x.Name).Select(o => new Organisation() { //populate with data from o, using OrderBy when needed });`. However you should probably reconsider your design. – BartoszKP Sep 17 '13 at 15:18
  • @ChrisHardie can't do that. The client needs a sorted dictionary. – haroonxml Sep 17 '13 at 15:36
  • @BartoszKP I will try your suggestion. – haroonxml Sep 17 '13 at 15:37

5 Answers5

13

I know this is an old question, but there's a simpler way of achieving the same result:

organisations = organisations.OrderBy(org =>
{
   org.Departments = org.Departments
   .OrderBy(dept =>
   {
     dept.Employees = dept.Employees
                     .OrderBy(employee => employee.Code)
                     .ThenBy(employee=>employee.Name);
     return dept.Code;
   })
   .ThenBy(dept=>dept.Name);

   return org.Code;
})
.ThenBy(org=>org.Name); 
Hellraiser
  • 579
  • 7
  • 18
  • This is the best answer, in my opinion. There is a typo -- Departmets should be Departments and each of the "...ThenBy(...) needs to end with a .ToList(); – Tom Baxter Aug 21 '16 at 00:53
  • Thanks for pointing out the typo. As for the .ToList() I don't think it's really necessary. I'll check and let you know. – Hellraiser Aug 22 '16 at 06:57
6

You need to do all three levels of sorting inside the objects that you return, like this (I'll show only the "Retail", the "Institutional" needs to be sorted in the same way):

{
"Retail", organisations
    .Where(x => x.Type == "Retail")
    .OrderBy(x => x.Code).ThenBy(x => x.Name)
    .Select(x => new Organisation {
        x.Code
    ,   x.Type
    ,   x.Name
    ,   Departments = x.Departmentsd.OrderBy(d => d.Code).ThenBy(d => d.Name)
        .Select(d => new Department {
            d.Code
        ,   d.Name
        ,   Employees = d.Employees.OrderBy(e => e.Code).ThenBy(e => e.Name).ToList()
        })
    }).ToList()
}

Since you need to select this multiple times, you may want to wrap this code in a method, and use it from several spots, like this:

private Organisation SortedOrganisation(Organisation x) {
    return new Organisation {
        x.Code
    ,   x.Type
    ,   x.Name
    ,   Departments = x.Departmentsd.OrderBy(d => d.Code).ThenBy(d => d.Name)
        .Select(d => new Department {
            d.Code
        ,   d.Name
        ,   Employees = d.Employees.OrderBy(e => e.Code).ThenBy(e => e.Name).ToList()
        })
    };
}

...

var legalEntitiesCollectionByType = new Dictionary<string, ICollection<Organisation>>
        {
            {
                "Institutional", organisations
                    .Where(x => x.Type == "Institutional")
                    .OrderBy(x => x.Code).ThenBy(x => x.Name)
                    .Select(SortedOrganisation)
                    .ToList()
            },
            {
                "Retail", organisations
                    .Where(x => x.Type == "Retail")
                    .OrderBy(x => x.Code).ThenBy(x => x.Name)
                    .Select(SortedOrganisation)
                    .ToList()
            }
        };
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Your answer makes sense and I am working on your suggested solution but will get back to you shortly. Cheers – haroonxml Sep 17 '13 at 15:39
3

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));
Toto
  • 7,491
  • 18
  • 50
  • 72
  • why use comparer when you have all that functionality implemented within linq ? . Linq's orderby does the job pretty well. – haroonxml Sep 18 '13 at 09:08
  • Because 'orderby' does not order 'in place', it generates a new IEnumerable and I need to assign it. 'Sort' method, on the contrary, does the job 'in place'. – Toto Sep 18 '13 at 12:08
  • These guys are same something else http://stackoverflow.com/questions/3378603/linq-orderby-vs-icomparer – haroonxml Sep 18 '13 at 13:18
2

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);
    }
}
Dialecticus
  • 16,400
  • 7
  • 43
  • 103
  • thanks for your suggestion but if i am using linq orderby i shouldnt have the need to implement an IComparer. – haroonxml Sep 18 '13 at 08:35
  • @HaroonEmmanuel, if the list is always required to be sorted then it makes sense to sort it only once, rather than sort it with linq every time it's used. – Dialecticus Sep 18 '13 at 09:43
-1
var legalEntitiesCollectionByType = new Dictionary<string, ICollection<Organisation>>
            {
                {
                    "Institutional", organisations
                        .Where(x => x.Type == "Institutional")
                        .ToList()
                        .Select(o => new Organisation{Code = x.Code,Departaments = x.Departaments.OrderBy(c => c).ToList()  }).ToList()
                }
            }
Pratik
  • 944
  • 4
  • 20
  • 2
    Please provide more information in your answer. Why does this code work better/different than the accepted answer? – mhlz Apr 14 '15 at 12:21