I have two objects one is a car object and the other object I use to log how many car objects are on shift and record what properties these cars have.
public class Car
{
public int Id { get; set; }
public bool OnShift { get; set; }
public bool HasExtraBaggageSpace { get; set; }
}
public class Log
{
public DateTime TimeStamp { get; set; }
public int CarId { get; set; }
public bool HasExtraBaggageSpace { get; set; }
}
Every five minutes the app selects all the cars on shift and writes the information to a log object and inserts them into a List Logs.
After three weeks of logging I would now like to return a number which reflects the average of the last three weeks . Example:
How many cars with HasExtraBaggageSpace can I expect on a thursday at 14:00.
public class myApp
{
public class AverageReturnArgs
{
public int Hour { get; set; }
public int Minute { get; set; }
public int Count { get; set; }
}
public AverageReturnArgs GetAverage(List<Log> logs, DateTime TimeReq)
{
int hour = TimeReq.Hour;
int min = TimeReq.Minute;
var average = logs.GroupBy(grpByHourMin => new
{
hour = grpByHourMin.TimeStamp.Hour,
min = grpByHourMin.TimeStamp.Minute
}).Select(av => new AverageReturnArgs()
{
Hour = av.Key.hour,
Minute = av.Key.min,
Count = av.Average(x => x.HasExtraBaggageSpace)
});
}
}
This is producing a compiler error.
Count = av.Average(x => x.HasExtraBaggageSpace)
Any ideas how I could accomplish this?
How would you calculate the average of boolean values ?
I think the Count aggregate should be what you are looking for:
Count = av.Count(x => x.HasExtraBaggageSpace)
EDIT If you mean to calculate the percentage of cars having ExtraBaggageSpace you may try something like this :
Count = av.Average(x => x.HasExtraBaggageSpace ? 1 : 0)
With use of the ternary operator this expression convert your boolean value to an integer and calculate the average (that will be a Double).
EDIT 2
Here is what your line should look like.
Count should be made of type Double.
Count = av.Average(x => av.Count(y=>y.HasExtraBaggageSpace))
EDIT 3
Ok the logic was all wrong :
public AverageReturnArgs GetAverage(List<Log> logs, DateTime TimeReq)
{
int hour = TimeReq.Hour;
int min = TimeReq.Minute;
var average = logs
.Where(log => log.TimeStamp.Hour == hour && log.TimeStamp.Minute == min)
.GroupBy(grp => grp.TimeStamp)
.Select(av => new AverageReturnArgs()
{
Hour = hour,
Minute = min,
Count = av.Average(x => av.Count(y=>y.HasExtraBaggageSpace))
});
}
Related
Using Entity Framework Core 6 I have the entity:
public class Node {
public String Parameter { get; set; }
public String Period { get; set; }
public Decimal Value { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
The Period value can be:
M1 = 1 Minute
H1 = 1 Hour
D1 = 1 Day
For each pair (Parameter, Period) I need to find if I have the most recent 200 values.
For example, I need to find if I have the temperature for the previous 200 days:
Parameter = Temperature
Period = D1
I need to check all the pairs that don't satisfy this condition. I started with:
var stored = _context.Nodes
.GroupBy(x => new { x.Parameter, x.Period })
.Select(x => new {
Parameter = x.Key.Parameter,
Period = x.Key.Period,
Count = x.Count()
});
With this I have the count for each pair.
But I am not sure if they are sequential and reaching today.
I have a list of the following class:
public class Data
{
public string Sector { get; set; }
public string Company { get; set; }
public string Branch { get; set; }
public string Category { get; set; }
public string Item { get; set; }
public string Currency { get; set; }
public int Year { get; set; }
public int Quarter { get; set; }
public int Month { get; set; }
public double Amount { get; set; }
}
With the date range given by the user, I am bringing data on year and month basis. However there is no data for some year and month in the given date range.
var dateRange = new List<DateTime>();
for (DateTime date = Report.Parameter.BeginDate; date <= Report.Parameter.EndDate; date.AddMonths(1))
{
dateRange.Add(new DateTime(date.Year, date.Month, 1));
}
For each year and month in the given date range, I want the Data object to come with a Amount column of 0 (zero).
This data should be added once for each Sector, Company, Branch and Category columns.
Example:
How do I do this with linq?
If you really need to use Linq, it would look like this:
public void MyFunction(List<Data> userData)
{
var beginDate = DateTime.Today;
var endDate = DateTime.Today.AddYears(2);
var monthsApart = 12 * (beginDate.Year - endDate.Year) + beginDate.Month - endDate.Month;
var dateRange = Enumerable.Range(0, monthsApart).Select(offset => beginDate.AddMonths(offset));
var difference = dateRange.Where(item => !(userData.Any(uData => uData.Year == item.Year && uData.Month == item.Month)));
userData.AddRange(difference.Select(date => new Data() {Year = date.Year, Month = date.Month, Amount = 0}));
}
This is just an example. You need to add your logic, where it is needed.
You mentioned This data should be added once for each Sector, Company, Branch and Category columns
If you want to do this, you have to call
userData.AddRange(difference.Select(date => new Data() {Year = date.Year, Month = date.Month, Amount = 0}));
as many times as you have combinations of Sector, Company, Branch and Category.
I hope this helps to understand and my explanation is not too complex.
I've got this generic list:
private List<ItemsForMonthYear> _itemsForMonthYearList;
...which stores instantiations of this class:
public class ItemsForMonthYear
{
public String ItemDescription { get; set; }
public String monthYr { get; set; }
public int TotalPackages { get; set; }
public Decimal TotalPurchases { get; set; }
public Decimal AveragePrice { get; set; }
public Double PercentOfTotal { get; set; }
}
I need to calculate the totals for all the TotalPackages in the list for each month (separately). I've got a start with this:
private int GetGrandTotalPackagesForMonth(String YYYYMM)
{
return _itemsForMonthYearList.Sum(x => x.TotalPackages);
}
This, though, gets the Grand TotalPackages for all months; I just want (one at a time) the Grand Totals for a given month. I was hoping I could use "Where" something like this:
return _itemsForMonthYearList.Sum(x => x.TotalPackages).Where(x => x.monthYr == YYYYMM);
...but that is not available.
How can I restrict a summation to the specified month?
You should apply the filter first and then sum TotalPackages like:
return _itemsForMonthYearList.Where(x => x.monthYr == YYYYMM).Sum(x => x.TotalPackages);
Although not related, but if you want you can get the sum for each month in a single query using GroupBy like:
var sumForeachMonth = _itemsForMonthYearList.GroupBy(x => x.monthYr)
.Select(grp => new
{
Month = grp.Key,
Sum = grp.Sum(r => r.TotalPackages)
});
You have Where clause available for such operations
myList.Where(x => x. monthYr == "Nov-15").Sum(x => x.TotalPackages);
I have a list of this object:
public class Customer
{
public int Id { get; set; }
public string EmailAddress { get; set; }
public DateTime ServiceStartDate { get; set; }
public DateTime? BillingStartDate { get; set; }
public string Status { get; set; }
}
In preparation for making a chart displayed on a dashboard I am trying to condense this list into another list of this object:
public class DashboardCustomerConversions
{
public string Month { get; set; }
public int Trials { get; set; }
public int Purchased { get; set; }
}
Where the end result looks something like:
Month Trials Purchases
--------- ------ ---------
Dec 2010 390 250
Jan 2011 345 190
Feb 2011 576 340
I am having a hard time coming up with a LINQ statement that can achieve the desired end result. This statement is very close:
var list = from b in results
group b by new { b.ServiceStartDate.Year, b.ServiceStartDate.Month } into g
select new Test
{
Month = string.Format("{0} {1}", CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(g.Key.Month), g.Key.Year),
Trials = g.Count(),
Purchased = g.Count()
};
The obvious problem in is the "Purchased = g.Count()" line in that it just repeats the Trials result. I would like to count objects where the BillingStartDate.HasValue is true.
Is there a way to restructure the LINQ to make this work?
Edit: I would prefer a fluent style of syntax but I was unable to get the above to work. Answer in any variation would be great.
You need to pass a condition to the Count method.
Purchased = g.Count(q => q.BillingStartDate.HasValue)
So SLaks had the right solution. Here it is written in fluent syntax:
listOfCustomer.GroupBy(c => new { c.ServiceStartDate.Year, c.ServiceStartDate.Month })
.Select(group => new DashboardCustomerConversions()
{
Month = string.Format("{0} {1}", CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(group.Key.Month), group.Key.Year),
Trials = group.Count(),
Purchased = group.Count(c => c.BillingStartDate.HasValue)
});
How can I change this method so it also returns Max(t.StartTime) and Min(t.StartTime) with only using it in one line as below?
public IQueryable<Timetable> GetTimetables()
{
return from t in _entities.Timetables
select t;
}
/M
Off the top of my head (read: untested) and presuming StartTime is non-nullable:
public class TimetableWithMaxMin
{
public Timetable Timetable { get; set; }
public DateTime Max { get; set; }
public DateTime Min { get; set; }
}
public IQueryable<TimetableWithMaxMin> GetTimetables()
{
return from t in _entities.Timetables
select new TimetableWithMaxMin
{
Timetable = t,
Max = _entities.Timetables.Max(t => t.StartTime),
Min = _entities.Timetables.Min(t => t.StartTime)
};
}
This gets considerably more complicated when StartTime is nullable.
I don't know if this is applicable to Entity framework but with linq it's something like this
public IQueryable<Timetable> GetTimetables()
{
return from t in _entities.Timetables
select new {maxt = Max(t.StartTime), mint = Min(t.StartTime)};
}