LINQ OrderBy Name ThenBy ChildrenCollection.Name - c#

Is there any way in LINQ to do an OrderBy and then do a ThenBy with the ThenBy using the children of the parent object to do the secondary ordering?
_repository.GetActiveDepartmentGroupsWithDepartments().OrderBy(c => c.DepartmentGroupName).ThenBy(c => c.Departments.OrderBy(d => d.DepartmentName))
In the above case, c.Departments is an EntityCollection.
BTW: When I try the above and then do a ToList() on it, I get this error:
DbSortClause expressions must have a type that is order comparable.
Parameter name: key
Thanks in advance for any help or guidance.

It seems like you're trying to get a list of all departments ordered by group then department name. If so, then you probably want to do something like this:
var res = from c in _repository.GetActiveDepartmentGroupsWithDepartments()
from d in c.Departments
orderby c.DepartmentGroupName, d.DepartmentName
select d;
Or in method syntax:
var res = _repository.GetActiveDepartmentGroupsWithDepartments()
.SelectMany(c => c.Departments, (c,d) => new { c, d })
.OrderBy(x => x.c.DepartmentGroupName)
.ThenBy(x => x.d.DepartmentName)
.Select(x => x.d);

Since Deparment is a collection, you have to transform it to a scalar to use it for sorting.
One option is to select a single entity to in the collection, e.g. the name of the first department:
_repository.GetActiveDepartmentGroupsWithDepartments()
.OrderBy(c => c.DepartmentGroupName)
.ThenBy(c => c.Departments
.OrderBy(d => d.DepartmentName)
.FirstOrDefault()
.DepartmentName
)
Another option is to order by a property of the collection itself, e.g. the number of departments:
_repository.GetActiveDepartmentGroupsWithDepartments()
.OrderBy(c => c.DepartmentGroupName)
.ThenBy(c => c.Departments.Count())

Related

How to use LINQ to adjust result?

From this LINQ:
var inspectionItems = inspArchive.Select(x => x.InspectionItems);
I get this result in inspectionItems :
My question is how can I make using LINQ in elegant way to make from inspectionItems result above one array distincted by Id.
Like that:
You want the SelectMany() LINQ method:
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems);
If you only want distinct items by a particular property, then you can either implement an equality comparer to see if your inspection classes are equal, then call .Distinct(myInspectionEqualityComparer) at the end of your method chain, or you can do this:
var distinctInspectionItems = inspArchive.SelectMany(x => x.InspectionItems)
.GroupBy(i => i.Id)
.Select(group => group.First());
Without seeing more of your code, I think you want to use SelectMany and Distinct ?
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems).Distinct();
The question is unclear, but check if this works for you:
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems)
.GroupBy(x => x.ID)
.Select(g => g.First())
.ToArray();

c# and LINQ - convert IGrouping to List

I have the following code written to find common objects in a list of objects
https://dotnetfiddle.net/gCgNBf
..............................
var query = setOfPersons
.SelectMany(l => l.Select(l1 => l1))
.GroupBy(p => p.Id)
.Where(g => g.Count() == setOfPersons.Count);
After that, I need to convert "query" to a list of "Person" objects ( List ) to achieve something else.
I tried using "ToList()"... But it says:
" cannot convert IGrouping to a List ".
Can someone help me to fix it ?
Looking at your code it seems that what you are trying to achieve is to get the list of people that exist in each list. If so, you can use the following query:
var query = setOfPersons
.SelectMany(l => l.Select(l1 => l1))
.GroupBy(p => p.Id)
.Where(g => g.Count() == setOfPersons.Count)
.Select(x=>x.First()) // Select first person from the grouping - they all are identical
.ToList();
Console.WriteLine("These people appears in all set:");
foreach (var a in query)
{
Console.WriteLine("Id: {0} Name: {1}", a.Id, a.Name);
}
Here you select just a single item from each grouping, because they all are identical.

LINQ group by and order by in C#

I need to convert my city list into group by state and order by city within it.
I tried below one but not able to get it right. Would appreciate any help on this.
cities.GroupBy(g => g.state).Select(o => o.OrderBy(c => c.cityname));
Try below code
cities.GroupBy(g => g.state)
.Select(o =>new {
State = o.Key,
Cities = o.OrderBy(c => c.cityname).Tolist()})
.Tolist();
cits.OrderBy(d => d.cityname).GroupBy(d => d.state).SelectMany(g => g).ToList();
1 - Order by cityname first.
2 - Then group them according to state. Since you order first, groups are still ordered with respect to cityname property.
3 - Convert to single list. Otherwise, you will end up with list of groups.
Should work. I also advice using camel case notation for naming your variables.
The ToLookup function may give you what you need.
cities.ToLookup(c => c.state, c => c.city);
This will create an IGrouping<string, string> where you can iterate through the Key values (states) and operate on a set of city values.
To sort it first, just do cities.OrderBy(c => c.state).ThenBy(c => c.city).
Do the orderby first:
cities.OrderBy(c=>c.cityname).GroupBy (c => c.state);
You might want to order the states to so.
cities.OrderBy(c=>c.cityname).GroupBy (c => c.state).OrderBy (g => g.Key);

Why can I not use OrderBy() in this lambda expression?

How do I order the following? The orderBy doesnt recognise the x.Name.
var xRefsNames = db.CrossRefs.Where(x => pgNos.Contains(x.PG))
.Select(x => x.Name)
.Distinct()
.OrderBy(x=>x.Name);
Your select is projecting a different object, probably a string based on the name. You want to just order by x.
var xRefsNames = db.CrossRefs.Where(x => pgNos.Contains(x.PG))
.Select(x => x.Name)
.Distinct()
.OrderBy(x=>x);

Distinct in Linq query

How I can make this Distinct work:
var blockIdMap = (from panelEntry in panelEntries
select new {panelEntry.BlockNo, panelEntry.BlockID})
.Distinct()
.ToDictionary(mc => mc.BlockNo , mc => mc.BlockID);
I need to have only unique entries of BlockNo with it's BlockId because I enter them to Dictionary and BlockNo should be unique.
I want just to take the first one.
var blockIdMap = panelEntries.GroupBy(pe => pe.BlockNo)
.ToDictionary(k => k.Key, v => v.First())
In this case your linq query doesn't work beacuse .Distinct() method equals panelEntry.BlockNo and panelEntry.BlockID and not only panelEntry.BlockNo. So a solution could be use MoreLinq and the method .DistinctBy():
var blockIdMap = (from panelEntry in panelEntries
select new {panelEntry.BlockNo, panelEntry.BlockID})
.DistinctBy(mc => mc.BlockNo)
.ToDictionary(mc => mc.BlockNo , mc => mc.BlockID);

Categories