Linq Query to find min and max in a datatable - c#

I am fetching the attendance details of employees in a datatable .
It looks like this
Day SwipeTime
12/31/2012 11AM
12/31/2012 1PM
12/31/2012 7PM
12/31/2012 8PM
1/1/2012 2PM
1/1/2012 7PM
1/1/2012 8PM
1/2/2012 10AM
1/2/2012 8PM
I need to display the date and totalhours for an employee
where totalhours = lastswipe - firstwipe
my result would look like
Day TotalHours
12/31/2012 9
1/1/2012 6
1/2/2012 12
So i need to find min and max swipes grouped by date.
Please help me write the query

You can use Enumerable.GroupBy to group by date. Then you could create a Dictionary<DateTime,int> where the key is the date and the value are the total-hours for that date:
Dictionary<DateTime,int> dateGroups = table.AsEnumerable()
.GroupBy(r => r.Field<DateTime>("Date").Date)
.Select(g => new{
Date = g.Key,
TotalHours = g.Sum(r =>
DateTime.ParseExact(r.Field<string>("SwipeTime"),
"htt", CultureInfo.InvariantCulture).Hour)
}).ToDictionary(x => x.Date, x => x.TotalHours);
Edit: So, that was the TotalHours of the whole day, now the desired max-min calculation. You also have changed your desired timespan-format to "11:41 AM". Then i would use DateTime.Parse(str).TimeOfDay to get the timespan.
Dictionary<DateTime, int> dateGroups = table.AsEnumerable()
.GroupBy(r => r.Field<DateTime>("Date").Date)
.Select(g => new
{
Date = g.Key,
TotalHours =
(g.Max(r => DateTime.Parse(r.Field<string>("SwipeTime")).TimeOfDay)
- g.Min(r => DateTime.Parse(r.Field<string>("SwipeTime")).TimeOfDay)).Hours
}).ToDictionary(x => x.Date, x => x.TotalHours);

In this answer ordered list of times for day is created to avoid two things - parsing all rows twice, and creating two sets from parsed values to get max and min item. Also I do not parse day before grouping, because same date will have same string value.
var query = from row in table.AsEnumerable()
group row by row.Field<string>("Day") into g
let times = g.Select(r => DateTime.Parse(r.Field<string>("SwipeTime")))
.OrderBy(t => t.TimeOfDay)
.ToList()
select new
{
DateTime.Parse(g.Key).Date,
(times.Last() - times.First()).TotalHours
};
Result is a collection of anonymous objects with two properties DateTime Date and double TotalHours

Related

Get the earliest date with maximum occurrences from a list

I have a list which contains dates and the same date can be repeated multiple times.
List<DateTime> dates = new List<DateTime>();
foreach (List<string> l in reservations)
{
var start = Convert.ToDateTime(l.First());
var end = Convert.ToDateTime(l.Last());
for (var date = start.Date; date.Date <= end.Date; date = date.AddDays(1))
dates.Add(date);
}
I want to find the date with maximum occurrences. If there are multiple dates with the maximum occurrence, I need to get the earliest date. Here's the LINQ query I wrote:
DateTime max = dates.GroupBy(s => s)
.OrderByDescending(s => s.Count())
.ThenBy(s => s)
.First().Key;
Here I'm getting the error:
At least one object must implement IComparable.'
How do I do this?
#Servy is correct.
I would suggest:
DateTime max = dates.GroupBy(s => s)
.OrderByDescending(sg => sg.Count())
.ThenBy(sg => sg.Key)
.First().Key;
You're trying to order by a group of dates. An entire group of dates can't be compared to another group of dates (unless you supply a custom comparer).
You probably want to order on the group's key, which is a single date, not on the entire group.

LINQ group by hour and add missing integer values

I have written a code like below:
var hourlyData = ctx.Transactions
.GroupBy(x => x.TransactionDate.Value.Hour)
.Select(pr => new HourlyGraph {
Hour = pr.Key,
Sales = pr.Sum(x => x.QuantitySoldTransaction)
}).OrderBy(x => x.Hour).ToList();
hourlyData.AddRange(Enumerable.Range(0, 23).Except(hourlyData.Select(m => m.Hour))
.Select(i => new HourlyGraph() { Hour = i, Sales =0 }));
Basically what I'm trying to do is to group all of my transactions from 0-23 (hours) and then add the missing integer values (hours). Those who miss I'd like to assign value - missing hour(22 lets say and sales 0).
The method above that I wrote gives me completely wrong values...
P.S. I get 22 value in hours multiple times, even though it shouldn't be there... 22 should only be repeated once (or any other hour value)...

.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))...

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.

Linq to Entity Group by Date

Done a lot of research but still having a tough one with this. Consider a database which has a transactions table of "CreatedOn", "Amount", "Type". I need to be able to do an entity query to get transactions of a certain type grouped together by different date granularities (month / day etc).
So imagine a table with:
2011/1/22 $300 Deposit
2011/2/18 $340 Deposit
2011/3/6 $200 Other
2011/3/6 $100 Deposit
2011/3/7 $50 Deposit
I could have a query which would pull all deposits grouped by month so it could yield:
2011-1 $300 1deposit
2011-2 $340 1deposit
2011-3 $150 2deposits
How would I then adapt this query to be by day rather than month?
Here's my current block of code but I get an inner linq exception
Can't group on A1
var result = context.TransactionEntities.Where(d => d.Type == "Deposit")
.GroupBy(g => new { g.CreatedOn.Year, g.CreatedOn.Month })
.Select(g => new
{
DateKey = g.Key,
TotalDepositAmount = g.Sum(d => d.Amount),
DepositCount = g.Count()
}).ToList();
Note: I am currently using the MySql connector and I've read possibly this is a bug?
Func<DateTime, object> groupByClause;
if (groupByDay) groupByClause = date => date.Date;
else if (groupByMonth) groupByClause = date => new { date.Year, date.Month};
else throw new NotSupportedException("Some option should be chosen");
var result = data.Where(d => d.Type == "Deposit")
.GroupBy(groupByClause)
.Select(g => new { DateKey = g.Key,
TotalDepositAmount = g.Sum(d => d.Amount),
DepositCount = g.Count(),
});
Of course this should be checked whether linq-2-entities will accept it.
Check the code mentioned in my question: Group by Weeks in LINQ to Entities. It shows how you can group your data by days and months. Let me know if you have any other questions.
This is probably a bug in MySQL connector. My solution for that was to place .ToList() just before .GroupBy().

Categories