Linq average in Dictionary - c#

I have a Dictionary and want to get the average of attendances from a specific timeframe.
So far I have this working which gives me the numbers of attendances:
var vCounts = (from pil in planInfoList
from s in pil.Value
where (s.CheckInActualUtc.TimeOfDay >= TStart
&& s.CheckInActualUtc.TimeOfDay <= TEnd)
select s).Count();
The s.CheckInActualUtc is multiple dates.
How to get the avarage of attendances?
I have tried this, but this is a no go:
var vAverage = from pil in planInfoList
from s in pil.Value
where (s.CheckInActualUtc.TimeOfDay >= TStart
&& s.CheckInActualUtc.TimeOfDay <= TEnd)
group s by s.CheckInActualUtc.DayOfYear into g
select new { av = g.Average() };

If you mean, you want the average of the number of attendees per day:
var vAverage = (from pil in planInfoList
from s in pil.Value
where (s.CheckInActualUtc.TimeOfDay >= TStart
&& s.CheckInActualUtc.TimeOfDay <= TEnd)
group s by s.CheckInActualUtc.DayOfYear into g
select g.Count()).Average();

Related

LINQ Query to Filter then to a Model

How can I do this correctly?
This is failing because schedule-on does not exist within m from RR2.
var RR = (from m in DataContext.csrcallds
where m.scheduledon >= earliestDate
&& m.scheduledon <= objdate1.DateStart
&& m.assignto == 113
&& (SqlMethods.DateDiffDay(m.scheduledon, m.completedon) > 5)
select m
);
var RR2 = RR.Select(x => (GetBusinessDays((DateTime)x.scheduledon, (DateTime)x.completedon)) > 5).ToList());
var RnR = (from m in RR2
group m by new { m.scheduledon.Value.Year, m.scheduledon.Value.Month } into p
orderby p.Key.Year ascending, p.Key.Month ascending
select new Date1()
{
theDate = DateTime.Parse($"{p.Key.Month} - {p.Key.Year}"),
theCount = p.Count(),
theString = $"{p.Key.Month} - {p.Key.Year}"
});
I am trying to query all the results.
Then use my GetBusinessDay function to filter out the ones I don't need, gathering only the records within 5 business days.
Then put the results into my Model named Date1.
I'm trying to do it like this because I cannot use GetBusinessDays within an LINQ query.
So I'm trying to filter it outside of SQL, then group the records again.
How do I go about accomplishing this task?
You could add this to your SQL Query to filter out the weekend days.
SELECT *
FROM your_table
WHERE ((DATEPART(dw, date_created) + ##DATEFIRST) % 7) NOT IN (0, 1)
Or This
select [date_created]
from table
where DATENAME(WEEKDAY, [date_created]) <> 'Saturday'
and DATENAME(WEEKDAY, [date_created]) <> 'Sunday'
Or if you have to stick to LINQ try the ideas outlined here:
Linq query DateTime.Date.DayOfWeek
DateTime firstSunday = new DateTime(1753, 1, 7);
var bookings = from b in this.db.Bookings
where EntityFunctions.DiffDays(firstSunday, b.StartDateTime) % 7 == 1
select b;
Solved by using function workdays server side:
https://stackoverflow.com/a/252532/6157660
Allows me to make a simple LINQ query, and gives me what I need.
I did edit the function to remove the +1 from DateDiff. as same days should be 0 not 1.
Thank you guys for your help!
var RnR = (from m in DataContext.csrcallds
where m.scheduledon >= earliestDate
&& m.scheduledon <= objdate1.DateStart
&& m.assignto == 113
&& (DataContext.fn_WorkDays((DateTime)m.scheduledon, (DateTime)m.completedon)) > 5
group m by new { m.scheduledon.Value.Year, m.scheduledon.Value.Month } into p
orderby p.Key.Year ascending, p.Key.Month ascending
select new Date1()
{
theDate = DateTime.Parse($"{p.Key.Month} - {p.Key.Year}"),
theCount = p.Count(),
theString = $"{p.Key.Month} - {p.Key.Year}"
});

No data return when performing a self join

I have a table contain the payment records of agencies. I want to sum total payment of each agency into 2 columns, first is current day payment and second is the day before payment.
So I try the SQL like this.
select p1.UserName, p1.PaymentAmount, p2.PaymentAmount
from vw_Agency_Payment p1
join vw_Agency_Payment p2 on p1.UserName=p2.UserName
where p1.PaymentDate = '2014-08-07'
and p2.PaymentDate = '2014-08-08'
It is successful and return the data.
But when I convert it to Linq like below:
var yesterday = DateTime.Today.AddDays(-1);
var tomorrow = DateTime.Today.AddDays(1);
var agencyPayment = from y in db2.vw_Agency_Payment
join t in db2.vw_Agency_Payment on y.UserName equals t.UserName
where y.PaymentDate >= yesterday
&& y.PaymentDate < DateTime.Today
&& t.PaymentDate >= DateTime.Today
&& t.PaymentDate < tomorrow
select new AgencyPaymentModel
{
agencyUserCode = y.UserName,
yesterdayPayment = y.PaymentAmount,
todayPayment = t.PaymentAmount,
growth = (t.PaymentAmount - y.PaymentAmount) / y.PaymentAmount * 100
};
return View(agencyPayment.OrderByDescending(c => c.growth).Take(100).ToList());
It return no data.
I don't know what make it wrong!?
Why not the following code (taking the date part of datetime field)?
var yesterday = DateTime.Today.AddDays(-1);
var agencyPayment = from y in db2.vw_Agency_Payment
join t in db2.vw_Agency_Payment on y.UserName equals t.UserName
where y.PaymentDate.Date = yesterday
&& t.PaymentDate.Date = DateTime.Today
select new AgencyPaymentModel
{
agencyUserCode = y.UserName,
yesterdayPayment = y.PaymentAmount,
todayPayment = t.PaymentAmount,
growth = (t.PaymentAmount - y.PaymentAmount) / y.PaymentAmount * 100
};
return View(agencyPayment.OrderByDescending(c => c.growth).Take(100).ToList());
where y.PaymentDate >= yesterday
&& y.PaymentDate < DateTime.Today
&& t.PaymentDate >= DateTime.Today
&& t.PaymentDate < tomorrow
No result will satisfy this condition:
from line 1-2, PaymentDate is limited to yesterday... intersect with line 3 will narrow down to nothing.
Basically you need to draw a reasonable range.
Plus, snippet 2 contains more logic than snippet 1, you should test them under same conditions.

Linq DefaultValues on Join

I'm trying to get the total download count of my app for the last 30 days on different devices, i succeeded of returning the right query, by grouping by the number of days and joinning with an enumerable with the last thirty days. However I'm not able to format the output as i want. Let me share the query first with the presentation in LinqPad
var last_days = (from idx in Enumerable.Range(1, (DateTime.Now - DateTime.Now.AddDays(-30)).Days)
select new { day = DateTime.Now.AddDays(-30).AddDays(idx).Date});
var orders = (from od in Orders
group od by EntityFunctions.AddSeconds((DateTime?)new DateTime(1970,1,1,0,0,0,0), (int?)od.Created) into g
select new {
day = g.Key ,
web = g.Where( q => q.Source == "web").Count(),
ios = g.Where( q => q.Source == "ios").Count(),
android = g.Where( q => q.Source == "android").Count(),
total = g.Count()
}).OrderByDescending(q => q.day).Take(31);
var days=
(from d in last_days
join od in orders on d.day equals od.day into x
from od in x.DefaultIfEmpty()
select x );
days.Dump();
This is the result I get
Now, I want to format the final output to an IEnumerable of 5 columns(day, web, ios, android, total) regardless whether it was empty or not. So instead of the empty O sign, I get the date, and the web = ios = android = total = 0. How can I do this?
So on day without any downloads, I still get an entry with the date and platforms to 0.
This is hardly the most elegant solution, but something like this should work:
var days = last_days.Select(d =>
orders.DefaultIfEmpty(new {
day = d,
web = 0,
ios = 0,
android = 0,
total = 0
}).FirstOrDefault(od =>
od.day == d.Date));
The basic idea is to tell the generator what to fall back on, in each case, if an appropriate order entry cannot be found.
In retrospect, it's probably easier to start from a blank slate. What about something more like:
var last_30_days =
from idx in Enumerable.Range(1, 30)
orderby idx descending
select DateTime.Now.AddDays(idx - 30).Date;
var orders =
from date in last_30_days
let datesOrders = Orders.Where(order => order.Created == date)
select new Info()
{
Date = date,
Web = datesOrders.Where(q => q.Source == "web").Count(),
iOS = datesOrders.Where(q => q.Source == "ios").Count(),
Android = datesOrders.Where(q => q.Source == "android").Count(),
Total = datesOrders.Count()
};
What about selecting new DaySum { ord = (ord == null ? 0 : ord.Count) };
Instead of just
Select x
Got it right, generated sql is okay in complexity, was a bit rusty on linq i guess
var last_days = (from idx in Enumerable.Range(1, (DateTime.Now - DateTime.Now.AddDays(-31)).Days)
select new { day = DateTime.Now.AddDays(-31).AddDays(idx).Date});
var orders = (from od in Orders
where od.ServiceProviderID == 2
group od by new DateTime(1970,1,1,0,0,0,0).AddSeconds(od.Created).Date into g
select new {
day = (DateTime)g.Key ,
web = g.Where( q => q.Source == "web").Count(),
ios = g.Where( q => q.Source == "ios").Count(),
android = g.Where( q => q.Source == "android").Count(),
total = g.Count()
}).OrderByDescending(q => q.day).Take(32);
var days = (from d in last_days
join od in orders on d.day.Date equals od.day.Date into x
from od in x.DefaultIfEmpty()
select new {
day = d.day ,
web = (od == null) ? 0: od.web,
ios = (od == null) ? 0: od.ios,
android = (od == null) ? 0: od.android,
total = (od == null) ? 0 : od.total
} );
days.Dump();

Group and Aggregate with LINQ

I have a timesheet entries as below
ActivityCode : Duration
Project A: 12h:31mins
Project B: 00h:10mins
Project A: 01h:10mins
Project A: 12h:31mins
Project C: 12h:31mins
Project B: 00h:10mins
Project B: 01h:10mins
Project A: 12h:31mins
What is the correct way to group the projects and aggregate their total time spent? i'm trying the below
var summary = from entry in DbSet
where entry.Timesheet.UserID == userid &&
entry.Timesheet.DateSubmitted >= startdate &&
entry.Timesheet.DateSubmitted <= enddate
group entry by entry.ActivityCode.ActivityCode1
into groupEntry
select new TimeSheetSummary()
{
ActivityCode = groupEntry.Key,
HourSpent = Convert.ToInt32(groupEntry.Sum(x => x.Duration)),
Percentage = (Convert.ToInt32(groupEntry.Sum(x => x.Duration)) / 8) * 100,
MinuteSpent = Convert.ToInt32(groupEntry.Sum(x => x.Duration)) * 60,
};
If you want to get a percentage, get a count of the number of activites and use that to divide by.
Not sure if you will need a divide by 0 check here. I'm not sure what the second LINQ will do if there's no data to begin with. Not sure if that would raise an error or not.
Int32 numberOfProjects = (from entry in DbSet
where entry.Timesheet.UserID == userid &&
entry.Timesheet.DateSubmitted >= startdate &&
entry.Timesheet.DateSubmitted <= enddate
select entry.ActivityCode.ActivityCode1).Distinct().Count();
var summary = from entry in DbSet
where entry.Timesheet.UserID == userid &&
entry.Timesheet.DateSubmitted >= startdate &&
entry.Timesheet.DateSubmitted <= enddate
group entry by entry.ActivityCode.ActivityCode1
into groupEntry
select new TimeSheetSummary()
{
ActivityCode = groupEntry.Key,
HourSpent = Convert.ToInt32(groupEntry.Sum(x => x.Duration)),
Percentage = (Convert.ToInt32(groupEntry.Sum(x => x.Duration)) / numberOfProjects) * 100,
MinuteSpent = Convert.ToInt32(groupEntry.Sum(x => x.Duration)) * 60,
};
Here's what i found as answer based on the inputs by others in the thread. thanks!
var groupEntries = from entry in DbSet
where entry.Timesheet.UserID == userId &&
entry.Timesheet.TimeSheetDate <= endDate.Date &&
entry.Timesheet.TimeSheetDate >= startDate.Date
group entry by entry.ActivityCode
into groupEntry
select new
{
ActivityCode = groupEntry.Key,
Duration = Convert.ToInt16(groupEntry.Sum(r => r.Duration))
};
var totalDuration = groupEntries.Sum(r => r.Duration);
var result = from groupEntry in groupEntries
select new TimeSheetSummary()
{
ActivityCode = groupEntry.ActivityCode,
HourSpent = groupEntry.Duration / 60,
MinuteSpent = groupEntry.Duration % 60,
Percentage = groupEntry.Duration / totalDuration * 100
};

create a query for date and average values

I need to select date and average values from a datacontext's table and I need to group it by year and by month.
In SQL it will look like this
select Year(data) as years, Month(data) as months, Avg(value) as prices from Prices
group by Year(data),MONTH(data)
order by years, months
I've created a LINQ query
var query0 = from c in dc.Prices
where Convert.ToDateTime(c.data).CompareTo(left) >= 0
&& Convert.ToDateTime(c.data).CompareTo(right) <= 0
&& c.idsticker.Equals(x)
group c by new { ((DateTime)c.data).Year, ((DateTime)c.data).Month }
into groupMonthAvg
select groupMonthAvg;
But I don't know how to get average values in result
Use the Average function.
var query0 = from c in dc.Prices
where Convert.ToDateTime(c.data).CompareTo(left) >= 0
&& Convert.ToDateTime(c.data).CompareTo(right) <= 0
&& c.idsticker.Equals(x)
group c by new { ((DateTime)c.data).Year, ((DateTime)c.data).Month }
into groupMonthAvg
select new
{
years = groupMonthAvg.Key.Year,
months = groupMonthAvg.Key.Month,
prices = groupMonthAvg.Average(x=>x.value)
};
Just use the Average function in your select:
var query0 = from c in dc.Prices
where Convert.ToDateTime(c.data).CompareTo(left) >= 0
&& Convert.ToDateTime(c.data).CompareTo(right) <= 0
&& c.idsticker.Equals(x)
group c by new { ((DateTime)c.data).Year, ((DateTime)c.data).Month }
into groupMonthAvg
select new {
groupMonthAvg.Key.Year,
groupMonthAvg.Key.Month,
YearAverage = groupMonthAvg.Average(x=>x.Year),
MonthAverage = groupMonthAvg.Average(x=>x.Month)
};
This should do it:
var query0 = from c in dc.Prices
where Convert.ToDateTime(c.data).CompareTo(left) >= 0
&& Convert.ToDateTime(c.data).CompareTo(right) <= 0
&& c.idsticker.Equals(x)
group c by new { ((DateTime)c.data).Year, ((DateTime)c.data).Month }
into groupMonthAvg
select new { Year = groupMonthAvg.Key.Year, Month = groupMonthAvg.Key.Month, Average => groupMonthAvg.Average(i => i.value) };

Categories

Resources