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);
Related
Hello this is a LINQ Query but it doesn't sort properly because four different dates are involved.
var EventReportRemarks = (from i in _context.pm_main_repz
.Include(a => a.PM_Evt_Cat)
.Include(b => b.department)
.Include(c => c.employees)
.Include(d => d.provncs)
where i.department.DepartmentName == "Finance"
orderby i.English_seen_by_executive_on descending
orderby i.Brief_seen_by_executive_on descending
orderby i.French_seen_by_executive_on descending
orderby i.Russian_seen_by_executive_on descending
select i).ToList();
All i want is that it should somehow combine the four dates and sort them in group not one by one.
For Example, at the moment it sorts all English Reports based on the date that executive has seen it, then Brief Report and So on.
But i want that it should check which one is seen first and so on. For example if the first report which is seen is French, then Brief, then English then Russian, so it should sort it accordingly.
Is it Possible??
You need to have them all in one column. The approach I would do, assuming that the value of the respective cells is null, when you don't want them to show up in the order by:
var EventReportRemarks = (from i in _context.pm_main_repz
.Include(a => a.PM_Evt_Cat)
.Include(b => b.department)
.Include(c => c.employees)
.Include(d => d.provncs)
where i.department.DepartmentName == "Finance"
select new
{
Date =
(
i.English_seen_by_executive_on != null ? i.English_seen_by_executive_on :
i.Brief_seen_by_executive_on != null ? i.Brief_seen_by_executive_on :
i.French_seen_by_executive_on != null ? i.French_seen_by_executive_on :
i.Russian_seen_by_executive_on
)
}).ToList().OrderBy(a => a.Date);
In the select clause you could add more columns if you whish.
Reference taken from here.
Why not just use .Min() or .Max() on the dates and then .OrderBy() or .OrderByDescending() based on that?
Logic is creating a new Enumerable (here, an array) with the 4 dates for the current line, and calculate the Max/Min of the 4 dates: this results in getting the latest/earliest of the 4. Then order the records based on this value.
var EventReportRemarks = (from i in _context.pm_main_repz
.Include(a => a.PM_Evt_Cat)
.Include(b => b.department)
.Include(c => c.employees)
.Include(d => d.provncs)
where i.department.DepartmentName == "Finance"
select i)
.OrderBy(i => new[]{
i.English_seen_by_executive_on,
i.Brief_seen_by_executive_on,
i.French_seen_by_executive_on,
i.Russian_seen_by_executive_on
}.Max())
.ToList();
Your problem is not a problem if you use method syntax for your LINQ query instead of query syntax.
var EventReportRemarks = _context.pm_main_repz
.Where(rep => rep.Department.DepartmentName == "Finance")
.OrderByDescending(rep => rep.English_seen_by_executive_on)
.ThenByDescending(rep => rep.Brief_seen_by_executive_on)
.ThenByDescending(rep => rep.French_seen_by_executive_on descending)
.ThenByDescending(rep => resp.Russian_seen_by_executive_on descending)
.Select(rep => ...);
Optimization
One of the slower parts of a database query is the transport of selected data from the DBMS to your local process. Hence it is wise to limit the transported data to values you actually plan to use.
You transport way more data than you need to.
For example. Every pm_main_repz (my, you do love to use easy identifiers for your items, don't you?), every pm_main_repz has zero or more Employees. Every Employees belongs to exactly one pm_main_repz using a foreign key like pm_main_repzId.
If you use include to transport pm_main_repz 4 with his 1000 Employees every Employee will have a pm_main_repzId with value 4. You'll transport this value 1001 times, while 1 time would have been enough
Always use Select to select data from the database and Select only the properties you actually plan to use. Only use Include if you plan to update the fetched objects
Consider using a proper Select where you only select the items that you actually plan to use:
.Select(rep => new
{
// only Select the rep properties you actually plan to use:
Id = rep.Id,
Name = rep.Name,
...
Employees = rep.Employees.Select(employee => new
{
// again: select only the properties you plan to use
Id = employee.Id,
Name = employee.Name,
// not needed: foreign key to pm_main_repz
// pm_main_repzId = rep.pm_main_repzId,
})
.ToList(),
Department = new
{
Id = rep.Department,
...
}
// etc for pm_evt_cat and provencs
});
Suppose there are two properties in Myclass: Date, Symbol
I want to frequently convert between those two properties, but I find that
for List <Myclass> vector
if I use
vector.groupby(o => o.Date).Select(o => o)
the vector is no longer the type of List<IGrouping<string, Myclass>>
And if I want to convert groupby(o => o.Date) to groupby(o => o.Symbol)
I have to use
vector.groupby(o => o.Date).Selectmany(o => o).groupby(o => o.Symbol)
I try to use SortedList<Date, Myclass>, but I am not familiar with SortedList(actually, I don't know what's the difference between SortedList and Groupby).
Is there any effective way to achieve such effect, as I highly depend on the speed of running?
int volDay = 100;
Datetime today = new DateTime(2012, 1, 1);
//choose the effective database used today, that is the symbol with data more than volDay
var todayData = dataBase.Where(o => o.Date <= today).OrderByDescending(o => o.Date)
.GroupBy(o => o.Symbol).Select(o => o.Take(volDay))
.Where(o => o.Count() == volDay).SelectMany(o => o);
//Select symbols we want today
var symbolList = todayData
.Where(o => o.Date == today && o.Eqy_Dvd_Yld_12M > 0))
.OrderByDescending(o => o.CUR_MKT_CAP)
.Take((int)(1.5 * volDay)).Where(o => o.Close > o.DMA10)
.OrderBy(o => o.AnnualizedVolatility10)
.Take(volDay).Select(o => o.Symbol).ToList();
//Select the database again only for the symbols in symbolList
var portfolios = todayData.GroupBy(o => o.Symbol)
.Where(o=>symbolList.Contains(o.Key)).ToList();
This is my real code, dataBase is the total data, and I will run the cycle day by day(here just given a fixed day). The last List portfolios is the final goal I want obtain, you can ignore other properties, which are used for the selections under the collection of Date and Symbol
It may be faster, or at least easier to read, if you performed a .Distinct().
To get distinct Dates:
var distinctDates = vector.Select(o => o.Date).Distinct()
To get distinct Symbols:
var distinctSymbols = vector.Select(o => o.Symbol).Distinct()
I asked what you were trying to accomplish so that I can provide you with a useful answer. Do you need both values together? E.g., the unique set of symbols and dates? You should only need a single group by statement depending on what you are ultimately trying to achieve.
E.g., this question Group By Multiple Columns would be relevant if you want to group by multiple properties and track the two unique pieces of data. a .Distinct() after the grouping should still work.
I have a collection and I need to order it by descending date(DateProcessed field) using Linq, first I am grouping by two possible Keys: Booked or Empty. But the data it's not being ordered..
This is my expression:
IEnumerable<IGrouping<string, MyClassMongo>> sub = Model.MyCollection.GroupBy(f => f.IsBooked ? "Booked" : "Empty").OrderByDescending(f => f.FirstOrDefault().DateProcessed);
I'm confused because I am grouping first, I know that after grouping the collection is splitted in two(Booked and Empty) so I am not sure how to handle the sorting because I am grouping first
If you are querying in-memory collection, then just place ordering before grouping:
IEnumerable<IGrouping<string, MyClassMongo>> sub =
Model.MyCollection
.OrderByDescending(f => f.DateProcessed)
.GroupBy(f => f.IsBooked ? "Booked" : "Empty");
Items within each group will be sorted by DateProcessed.
if you want to first Group by and then sort the results within the Group. you can try some thing like below
Model.MyCollection
.GroupBy(f => f.IsBooked,
(f, g) => new{Key=f.DateProcessed, Group = g.OrderByDescending(c=>c.IsBooked)})
.OrderByDescending(f => f.Key);
PS: Code may have syntax issue not tested but the idea should be to create the key withing each group so we can order by
I'm trying to do a GroupBy and then OrderBy to a list I have. Here is my code so far:
reportList.GroupBy(x => x.Type).ToDictionary(y=>y.Key, z=>z.OrderBy(a=>a.Lost));
With the help of the last question I asked on linq I think the ToDictionary is probably unneeded, but without it I don't know how to access the inner value.
To be clear, I need to GroupBy the Type property and want the inner groups I get to be OrderBy the Lost property (an integer). I want to know if there is a better, more efficient way or at the least better then what I've done.
An explanation and not just an answer would be very much appreciated.
Yes, there is better approach. Do not use random names (x,y,z,a) for variables:
reportList.GroupBy(r => r.Type)
.ToDictionary(g => g.Key, g => g.OrderBy(r => r.Lost));
You can even use long names to make code more descriptive (depends on context in which you are creating query)
reportList.GroupBy(report => report.Type)
.ToDictionary(group => group.Key,
group => group.OrderBy(report => report.Lost));
Your code does basically the following things:
Group elements by type
Convert the GroupBy result into a dictionary where the values of the dictionary are IEnumerables coming from a call to OrderBy
As far as the code correctness it is perfectly fine IMO, but maybe can be improved in term of efficiency (even if depends on your needs).
In fact, with your code, the values of your dictionary are lazily evaluated each time you enumerate them, resulting in a call to OrderBy method.
Probably you could perform it once and store the result in this way:
var dict = reportList
.GroupBy(x => x.Type)
.ToDictionary(y => y.Key, z => z.OrderBy(a => a.Lost).ToList());
// note the ToList call
or in this way:
var dict = reportList.OrderBy(a => a.Lost)
.GroupBy(x => x.Type)
.ToDictionary(y => y.Key, z => z);
// here we order then we group,
// since GroupBy guarantees to preserve the original order
Looks fine to me. If you use an anonymous type instead of a Dictionary, you could probably improve the readability of the code that uses the results of this query.
reportList.GroupBy(r => r.Type)
.Select(g => new { Type = g.Key, Reports = g.OrderBy(r => r.Lost) });
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())