Get the earliest date in a LINQ expression - c#

I have the following LINQ in a WebAPI controller:
MyDate = i.Products.FirstOrDefault().Date
It works as expected. But, Products is a Collection, so there can be many dates. The above just selects the first one.
What I really want to do is to find the date, with the earliest time, and select that one.
How would that look?

If you only want the date and not the whole product, it's a little clearer to use Max or Min.
MyDate = i.Products.Select(x => x.Date).Max()
If you actually want the product, you'll need to sort by the date and then select the first one.
MyProduct = i.Products.OrderBy(x => x.Date).FirstOrDefault()

This way is more concise:
var earlyDate = i.Products.Min(p=>p.Date);
But you are sure that Product != null

You can use
i.Products.OrderByDescending(x => x.Date).FirstOrDefault().Date;

Here is a lambda expression that will give you the minimum (earliest) date
DateTime earliestDate = i.Products.Min(p => p.Date);

Simple, if you need earliest use OrderBy and need oldest then use OrderByDescending.
i.Products.OrderBy(x => x.Date).Select(x => x.Date).FirstOrDefault();
i.Products.OrderByDescending(x => x.Date).Select(x => x.Date).FirstOrDefault();

Simply order by date:
MyDate = i.Products.OrderBy(x => x.Date).Select(x => x.Date).FirstOrDefault();

Optimized way would be :
i.Products.OrderByDescending(x => x.Date).Select(x => x.Date).FirstOrDefault();

i.Products.OrderBy(x => x.Date).FirstOrDefault().Date;
It has to be orderby and not orderbydescending. orderbydescending will give you the latest date first and order by will give you the earliest date first.

Related

.NET when grouping records by hour impossible to use datetime in the select

I'm trying to group a list of records by hour and store the number of record for each hour. Here is my code :
DateTime firstTimeStamp = myRecords.DataBaseRecords.First().TimeStamp;
Statistics = myRecords.DataBaseRecords
.GroupBy(x => x.TimeStamp.Hour)
.Select(group => new GraphModel() { Date =firstTimeStamp.AddHours(group.Key), Value = group.Count() })
.ToList();
The problem is that when I'm on the select fuction, I cannot acces to the DateTime anymore so the field group.key contains a value between 0 and 24. I just need to group all the records by hour and foreach hour, I need to have the number of records in the Value parameter.
You have to group the data by absolute hours as of the first timestamp, i.e. the differences in hours calculated for each TimeStamp value:
Statistics = myRecords.DataBaseRecords
.GroupBy(x => DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp) into g
.Select(g => new GraphModel
{
Date = g.FirstOrDefault().TimeStamp,
Value = g.Count()
};
If this is plain LINQ to objects (not Entity Framework) you can replace ...
DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp)
... by
(x.TimeStamp - firstTimeStamp).TotalHours
If it's LINQ to SQL, use
SqlMethods.DateDiffHour(firstTimeStamp, x.TimeStamp)
Perhaps something like this may work out for you:
DateTime myDateTime = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key).Ticks);
Question specific to answer above:
...Date = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key))...

Group by year descending, order by month and total on another column Linq query

Have this Linq query almost working, can't figure out how to do the descending order. Here is what I have so far:
list.GroupBy(grp => grp.year)
.SelectMany(g => g.OrderBy(grp => grp.month))
.ToList();
Which produces the following results:
Month is in the correct order except the year needs to be in descending order. Like this:
This might be too much to ask but also need to run a total of days per grouped year. Really appreciate any help!
The data looks like this:
The answer the worked for me was this:
list.OrderByDescending(grp => grp.year).ThenBy(grp => grp.month).ToList()
Two comments:
You are "grouping" your data, then turning around and un-grouping via a SelectMany, which effectively throws away any grouping; it just puts the data into groups, but not in any configurable order. Just select all of your data in one go, ordering by year descending, then month:
list.OrderByDescending(l => l.year)
.ThenBy(l => l.month));
Adding "group footers" to show subtotals is the job of the presentation layer, not the data layer. You could create a hybrid list that inserts a total "row" into your data, but it is probably more straightforward to add a group footer by configuring whatever control is presenting the data rather than inserting subtotals into the raw data.
You need to add .ThenByDescending(grp => grp.year) after your OrderBy expression, so like this:
list.GroupBy(grp => grp.year)
.SelectMany(g => g.OrderBy(grp => grp.month).ThenByDescending(grp => grp.year))
.ToList();
To achieve what you want, first, OrderBy Year, ThenBy Month
See code below:
list.OrderByDescending(grp => grp.year).ThenBy(grp => grp.month)
.GroupBy(grp => grp.year)
.SelectMany(g => g)
.ToList();
If you want to get total days per grouped year, you can do this like that:
list.OrderByDescending(grp => grp.Year).ThenBy(grp => grp.Month)
.GroupBy(grp => grp.Year)
.Select(g => new { Year = g.Key, Months = g, TotalDays = g.Sum(d => DateTime.DaysInMonth(d.Year, d.Month)) })
.ToList();
So you will have a collection of object that have 3 properties
Year
Months that is a collection of dates
TotalDays that is the total of days from this grouped year

Entity Framework - Select single record ordered by a property

I have a table and one of the properties of the table is TotalDue.I wish to first order it by TotalDue and then select the "top" record which in this case would be the record with the highest value.
homeVM.LastSaleAmount = (from i in salesService.GetSalesOrderHeaders()
.OrderByDescending(a => a.TotalDue).First();
This is what I've tried so far but I think .First() needs a parameter and I think I need a select as well but not really sure.
You can try with Take method, is like top, but in Linq world.
homeVM.LastSaleAmount = salesService.GetSalesOrderHeaders().OrderByDescending(a => a.TotalDue).Take(1);
https://msdn.microsoft.com/en-us/library/vstudio/bb503062%28v=vs.100%29.aspx
You're mixing method syntax and query syntax, and your use of query syntax isn't necessary and making this harder. Just remove it:
homeVM.LastSaleAmount = salesService.GetSalesOrderHeaders()
.OrderByDescending(a => a.TotalDue)
.Select(a => a.TotalDue)
.First();
You are trying to put an entire entity into LastSaleAmount. use .Select(a => a.TotalDue) like:
homeVM.LastSaleAmount = salesService.GetSalesOrderHeaders()
.OrderByDescending(a => a.TotalDue).Select(a => a.TotalDue).First();

linq select where between dates

I'm trying to add to the dates all the events between Date and DateFinal in order to fill the calendar with the events.
I've already searched but I can't find any solution for this.
pageItems.Add("dates", allEvents.Select(i => i.Date).ToList());
This is what I have so far but only show the days of i.Date and I want to show all of the days between Date and DateFinal.
Cheers and thanks in advance
In the allEvents I have
allEvents = Current.Descendants(n => n.NodeTypeAlias == "EventPage")
.get_Items()
.Select(n => new{
Node = n,
Date = (Helper.ParseXmlDate(n.GetProperty("itemDate")) ?? n.UpdateDate).DatePart(),
DateFinal = (Helper.ParseXmlDate(n.GetProperty("itemDateFinal")) ?? n.UpdateDate).DatePart()
});
Use this:
allEvents.Where(i => i.Date > Date && i.Date < DateFinal).Select(i => i.Date).ToList()
First.. Sorry if I have misunderstood the question
If you have 2 DateTime and you want to select a list of all the Days(as DateTime) between those 2 dates, you could use Enumerable.Range using the amount of days between the Date and DateFinal to loop in your select statement to add a day to the start date and output a list of DateTimes
This will select all the dates between Date and DateFinal.
allevents.Select(i => Enumerable.Range(1, (i.DateFinal - i.Date).Days).Select(dayCount => i.Date.AddDays(dayCount))).ToList()
If you need to include Date and DateFinal to the list you can use
allevents.Select(i => Enumerable.Range(0, 1 + (i.DateFinal - i.Date).Days).Select(dayCount => i.Date.AddDays(dayCount))).ToList()
Input:
Date: 02/20/2013
DateFinal: 02/31/2013
OutPut:
02/20/2013
02/21/2013
02/22/2013
02/23/2013
...
Is that what you mean?
You probably searching for:
TimeSpan span=d2-d1;
span.TotalDays;
so it should look like:
allEvents.Select(i => (DateFinal - i.Date).TotalDays).ToList()
This shows all days between some DateFinal and i.Date
If this is not what you're searching for, please clarify.

How to order by a date part?

I have a DataColumn of DateTime datatype and I want to order by the year in descending order followed by the month in descending order.
Here's what I tried:
table.AsEnumerable()
.OrderByDescending(o => o.Field<DateTime>("MaxDateTaken").Year)
.ThenByDescending(o => o.Field<DateTime>("MaxDateTaken").Month)
I get an invalid cast error because both Year and Month are int datatypes, but I'm specifying DateTime in the <>
Any ideas?
You shouldn't get a cast error because of that - are you sure that field is really a DateTime?
It sounds like you really just want
table.AsEnumerable()
.OrderByDescending(o => o.Field<DateTime>("MaxDateTaken"))
anyway, given that ordering by the year and the month descending is basically ordering by the date descending, except it doesn't do anything with the "day" part. Do you really not want to include the "day" part in your ordering?
Why are you ignoring the day part? It could get simpler:
table = table.AsEnumerable()
.OrderByDescending(o => DateTime.Parse(o.Field<string>("MaxDateTaken")))
I fixed it like this:
table = table.AsEnumerable()
.OrderByDescending(o => DateTime.Parse(o.Field<string>("MaxDateTaken")).Year)
.OrderByDescending(o => DateTime.Parse(o.Field<string>("MaxDateTaken")).Month)

Categories