Reputation: 11
I have 2 tables in the database Department and SubDepartment. Each department can or cannot have multiple sub departments. I am fetching the data from both the tables combined in the form of following class.
This class have more properties as well from both the tables.
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public int SubDepartmentId { get; set; }
public string SubDepartmentName { get; set; }
}
For example data can be Department as Science which will have multiple Sub Departments as Physics, Chemistry. Also Department can be English which will have one sub department as English only.
Now from the data in the form of List of Departments collection fetched from the DB I have to fetch those departments which have multiple sub departments.
Below is the code:
List<Department> departments = new List<Department>();
// Here fetching deptids which are having multi sub deptids
var multidepartmentIds = departments .GroupBy(x => x.DepartmentId)
.Where(x => x.Count() > 1)
.Select(x => new { DepartmentId = x.Key }).ToList();
// Here getting the entire data/item for each dept and subdept
var finalDeptData = departments.Where(x => multidepartmentIds.Any(y => y.DepartmentId == x.DepartmentId)).ToList();
Is there a better way to implement this?
I have thought of one more way as well where in a single lambda statement after Count we can have an anonymous type with all the class properties but the problem is that I have to return this collection to the caller method and then in that case I have to return the anonymous collection as type object which will require changes in the caller method as well.
Any help??
Upvotes: 1
Views: 851
Reputation: 1335
Looking at your code, IMO you are trying to get a list of all sub-departments which their department has multiple sub-department. In this case, you can do this:
List<Department> departments = new List<Department>();
// Here fetching deptids which are having multi sub deptids
var multidepartmentIds = departments
.GroupBy(x => x.DepartmentId)
.Where(x => x.Count() > 1)
.SelectMany(x => x)
.ToList();
Upvotes: 1
Reputation: 26917
There is no need to create an anonymous type to hold a single value. Since you are looking for matches in the collection of IDs, use a HashSet
to hold them:
// Here fetching deptids which are having multi sub deptids
var multidepartmentIds = departments.GroupBy(d => d.DepartmentId)
.Where(dg => dg.Count() > 1)
.Select(dg => dg.Key)
.ToHashSet();
// Here getting the entire data/item for each dept and subdept
var finalDeptData = departments.Where(d => multidepartmentIds.Contains(d.DepartmentId)).ToList();
However, since all you really want is all the departments
where there are multiple occurrences, you can do that in one statement:
// find all departments with multiple sub deptids and return them
var finalDeptData2 = departments.GroupBy(d => d.DepartmentId)
.Where(dg => dg.Count() > 1)
.SelectMany(dg => dg)
.ToList();
I like to have an extension method for this:
public static class IEnumerableExt {
public static IEnumerable<T> DuplicatesBy<T,TKey>(this IEnumerable<T> src, Func<T,TKey> keyFn, IEqualityComparer<TKey> comparer = null)
=> src.GroupBy(s => keyFn(s), comparer).Where(sg => sg.Count() > 1).SelectMany(sg => sg);
}
Which you can use like:
var findDeptData3 = departments.DuplicatesBy(d => d.DepartmentId).ToList();
Upvotes: 0