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
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.
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.
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.
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));
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With