Find if list is sequential and with timestamp to today - c#

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.

Related

Aggregate and create results list using EF

I'm having a list of budget units each one containing the following properties:
DateTime Month,
int IdCurrency,
decimal Planned,
int sign, //denotes whether we have income (1) or cost (0)
etc...
Based on given year, I'd like to return a list of objects of the following structure:
public class BudgetBalances
{
public DateTime Month { get; set; }
public int IdCurrency { get; set; }
public decimal Incomes { get; set; }
public decimal Costs { get; set; }
public decimal Balance { get; set; }
}
The first part is easy - I'm getting all budget units for given day from the database, but now I do not know how to make an EF query to:
Get all incomes (sign==1) in currencies within one month, sum them and store it Incomes property
Get all costs (sign==0) and do the same as above
Substract Cost from Income and store it under Balance property
As the result I will have
Jan2022, USD, 3000, 1000, 2000
Jan2022, EUR, 5000, 2000, 3000
etc..
I can always make three level foreach structure, but that is not an effective way to do so. Could you please give me hint how to do it proper way?
That is what I got so far:
public List<BudgetBalances>GetYearlyBudget(int IdOwner, int year)
{
var budgets = _context.Budgets
.Where(_ => _.Month.Year == year && _.IdOwner == IdOwner);
List<BudgetBalances> list = budgets.GroupBy(a => a.Month)
.Select(ls => new BudgetBalances
{
Incomes = ls.Where(_ => _.IsIncome == 1).Sum(_ => _.Planned),
Costs = ls.Where(_ => _.IsIncome == 0).Sum(_ => _.Planned)
}).ToList();
return list;
}
And it calculates each month budget taking into account incomes and costs, but it does not take currencies into consideration. Also I do not know how should I obtain balance value.
Balance = Income - Costs
does not work
Reference this
code sample
using (var context = new MyContext())
{
var result = context.BudgetBalances
.Where(b => b.IdCurrency == 1);
}
Thanks, finally I got what I wanted, here's my code:
public List<BudgetBalances>GetYearlyBudget(int IdOwner, int year)
{
var budgets = _context.Budgets
.Where(_ => _.Month.Year == year && _.IdOwner == IdOwner);
List<BudgetBalances> list = budgets.GroupBy(a => new { a.Month, a.IdCurrency})
.Select(ls => new BudgetBalances
{
IdCurrency = ls.Key.IdCurrency,
CurrencySymbol = _context.Currencies.Where(_=>_.IdCurrency==ls.Key.IdCurrency).FirstOrDefault().CurrencySymbol,
Month = ls.Key.Month,
Incomes = ls.Where(_ => _.IsIncome == 1).Sum(_ => _.Planned),
Costs = ls.Where(_ => _.IsIncome == 0).Sum(_ => _.Planned),
})
.OrderBy(_=>_.Month)
.ToList();
foreach(BudgetBalances ls in list)
{
ls.Balance = ls.Incomes - ls.Costs;
ls.month = ls.Month.ToString("MM/yyyy");
}
return list;
}

How to count rows of a table grouped by shortdatestring?

We have an database with an this structure:
public partial class ChartData
{
public int Id { get; set; }
public DateTime Timestamp { get; set; }
public string Function { get; set; }
public int Duration { get; set; }
public bool IsError { get; set; }
}
Now we want to group the entries of this database by Timestamp.ToShortDateString() and then count the entries belonging to this date.
So for example we have:
2019-06-04 11:54:02,135,someFunction,30,False,
2019-06-04 11:55:03,135,someFunction,230,False,
2019-06-04 11:56:03,150,someFunction,4,True,
2019-06-05 11:54:03,230,someFunction,46,False,
2019-06-05 11:55:03,230,someFunction,46,False,
And I want this result:
{date: 2019-06-04, rows: 3}
{date: 2019-06-05, rows: 2}
public List <LogFileDTO> GetLogFilesData()
{
var items = db.ChartDatas.GroupBy(x = > new {
x.Timestamp.ToShortDateString
}).Select(x = > new LogFileDTO {
date = x.Timestamp.First(),
rows = x.Count ?
}).ToList();
}
So I do not really know how to group this input by date and then count the rows of each group.
You simply need to group on the Date property of the TimeStamp and then project using Select on the Key of each IGropuing and Count like below :
var items = db.ChartDatas.GroupBy(x => x.Timestamp.Date) // group only on Date
.Select(x => new LogFileDTO
{
Date = x.Key.ToShortDateString(),
Rows = x.Count()
}).ToList();
Key will contain only date part of DateTime object and Count() will tell the number of rows for that date in the group.
Hope it helps!

Calculating price ranges with LINQ and corresponding sale numbers

to start things off I have a class which basically represents all the transactions for specific items, it's usually 100 items for which I have transactions. The class looks as following:
public class RawTransactions
{
public string SellerName { get; set; }
public int FeedBackScore { get; set; }
public int QuantityPurchased { get; set; }
public DateTime TransactionDate { get; set; }
public string ProductTitle { get; set; }
public double CurrentPrice { get; set; }
public double SalePrice { get; set; }
public string ItemID { get; set; }
public string Date { get; set; }
}
Based on this class and the transactions inside a list of this type I've created a function which basically takes smallest and largest sale price of any transaction that is present in the list and creates a 7 stage price range
private List<double> GetRangeForElements(double minPrice, double maxPrice)
{
double step = (maxPrice - minPrice) / 7.00d;
return Enumerable.Range(0, 8).Select(i => minPrice + i * step).ToList();
}
So for example if I pass $0 (smallest sale price) and $10 (largest sale price) it will create a list of 7 price range like following:
0
1.5
3
4.5
6
7.5
9
10
This can be interpreted as:
0 - 1.5 price range
1.5 - 3 price range
3 - 4.5 price range
4.5 - 6 price range
6 - 7.5 price range
// and so on...
The usage is as following:
var ranges = GetRangeForElements(0,10); // Here I will have the ranges now
Now based on these ranges that were just created and the existing transactions that I have I need to determine following parameters:
Price range
How many sales specific ItemID has sales for a specific range
How many sellers (based on SellerName property) had sales for a specific price range
How many sellers (again based on SellerName propert) DIDN'T had sales for a specific price range
I'm not really sure how can I now combine all this data to get these parameters using LINQ? Can someone help me out with this?
P.S. guys the transactions of all items are stored in a List like following:
var allItemsTransactions = new List<ProductResearchRawTransactions>();
P.S. guys this is the existing solution that I have, but it's giving me completely wrong results:
var priceRanges = ranges.Select(r => new PriceRangeGraph
{
Price = Math.Round(r, 2),
Sales = allItemsTransactions.Where(x => ranges.FirstOrDefault(y => y >= x.SalePrice) == r).Sum(x => x.QuantityPurchased),
SuccessfulSellers = allItemsTransactions.Where(x => ranges.FirstOrDefault(y => y >= x.SalePrice) == r).GroupBy(x => new { x.SellerName, x.QuantityPurchased }).Where(x => x.Key.QuantityPurchased > 0).Select(x => x.Key.SellerName).Count(),
UnSuccessfulSellers = allItemsTransactions.Where(x => ranges.FirstOrDefault(y => y >= x.SalePrice) == r).GroupBy(x => new { x.SellerName, x.QuantityPurchased }).Where(x => x.Key.QuantityPurchased == 0).Select(x => x.Key.SellerName).Count(),
}).ToList();

Linq Grouping and averages

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))
});
}

How can I get two different aggregates in a single LINQ?

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)
});

Categories