Call function inside linq query - c#

I have list of object and i want to filter this to between to date.
I write function for this if date is between to dates return true else return false.
This is my function.
private bool IsDateBetween(DateTime date, string min, string max) {
bool resultMin = true;
bool resultMax = true;
if (!string.IsNullOrEmpty(min))
{
resultMin = date > Convert.ToDateTime(min);
}
if (!string.IsNullOrEmpty(max)) {
resultMax = date < Convert.ToDateTime(max);
}
return resultMin&&resultMax;
}
and this is how i call function with linq.
var policiesT = policies.Where(x=>IsDateBetween(x.StartofInsurance,startDateS,startDateF));
startDateS and startDateF is string of datetime and i checked that values.
They have value when i run the code.
But problem is when i debug the function min and max values always coming null.
This is the image before the calling function
This is the image when function is running.
Why that values caming null can u helpp me. Thanks

This maybe not an answer but in comments would be a mess. This sample works fine for me:
void Main()
{
var policies = new List<Policy> {
new Policy {StartofInsurance=new DateTime(2021,1,1)},
new Policy {StartofInsurance=new DateTime(2021,6,21)},
new Policy {StartofInsurance=new DateTime(2021,7,13)},
};
string startDateS = "01/09/2021";
string startDateF = "07/01/2021";
var policiesT = policies.Where(x => IsDateBetween(x.StartofInsurance, startDateS, startDateF));
foreach (var p in policiesT)
{
Console.WriteLine(p.StartofInsurance);
}
}
private bool IsDateBetween(DateTime date, string min, string max)
{
bool resultMin = true;
bool resultMax = true;
if (!string.IsNullOrEmpty(min))
{
resultMin = date > Convert.ToDateTime(min);
}
if (!string.IsNullOrEmpty(max))
{
resultMax = date < Convert.ToDateTime(max);
}
return resultMin && resultMax;
}
public class Policy
{
public DateTime StartofInsurance { get; set; }
}
And returns the correct policy:
6/21/2021 12:00:00 AM

Related

Return false if type properties equals null or 0

I tried following the method as follows here: Checking if Object has null in every property . However, when instantiating Order newOrder = new Order();. I cannot simple just implement bool props = newOrder.ArePropertiesNotNull(). What am I supposed to add to my Order class? And where do I implement the function for ArePropertiesNotNull<T>(this T obj)? I would like to know if there is a way to return false if value returned equals 0 or null?
Here is my code:
OrderProdRepository.cs
...
public bool ReadFromFile(string _date)
{
taxesFile.ReadFile();
productsFile.ReadFile();
string orderFileName = $"C:\\tempfolder\\Orders_{_date}.txt";
List<string> lines = File.ReadAllLines(orderFileName).ToList();
foreach (var line in lines.Skip(1)) //?? new List<string>(0)
{
List<string> entry = line.Split(',').ToList();
Order newOrder = new Order();
int.TryParse(entry[0], out int orderNumber);
newOrder.OrderNumber = orderNumber;
newOrder.Date = _date;
newOrder.CustomerName = entry[1];
newOrder.State = taxesFile.StateAbbreviation(entry[2]);
newOrder.StateName = taxesFile.StateName(newOrder.State);
decimal.TryParse(entry[3], out decimal taxRate);
newOrder.TaxRate = taxesFile.TaxRate(taxRate);
newOrder.ProductType = productsFile.ProductType(entry[4]);
decimal.TryParse(entry[5], out decimal area);
newOrder.Area = area;
decimal.TryParse(entry[6], out decimal costPerSquareFoot);
newOrder.CostPerSquareFoot = productsFile.CostPerSquareFoot(costPerSquareFoot);
decimal.TryParse(entry[7], out decimal laborCostPerSquareFoot);
newOrder.LaborCostPerSquareFoot = productsFile.LaborCostPerSquareFoot(laborCostPerSquareFoot);
decimal.TryParse(entry[8], out decimal materialCost);
newOrder.MaterialCost = materialCost;
decimal.TryParse(entry[9], out decimal laborCost);
newOrder.LaborCost = laborCost;
decimal.TryParse(entry[10], out decimal tax);
newOrder.Tax = tax;
decimal.TryParse(entry[11], out decimal total);
newOrder.Total = total;
orderList.Add(newOrder);
}
return true;
}
...
I think you need a function to check each line for null and/or 0 values:
private bool IsValidLine(string line)
{
if (line == null)
return false;
var arr = line.Split(',');
//Uncomment this if splitting the line will always return 11 items array.
//if (arr.Length < 11)
// return false;
return arr.Aggregate(0, (n, s) =>
(decimal.TryParse(s, out decimal d) && d == 0) ||
string.IsNullOrWhiteSpace(s) ? n + 1 : n) == 0;
}
You can use it in your code as follows:
public bool ReadFromFile(string _date)
{
var orderFileName = $"C:\\tempfolder\\Orders_{_date}.txt";
var lines = File.ReadAllLines(orderFileName);
foreach (var line in lines.Skip(1))
{
//If parsing any line returns false.
if (!IsValidLine(line))
return false;
//Or if you need to create a list of the valid Order entries.
if (IsValidLine(line))
{
var order = new Order();
//...
orderList.Add(newOrder);
}
}
return true;
}
Alternatives:
Add a static function in the Order class to parse a given line and return a new object of Order type if the line is valid. Something like this.
If its not too late, then consider using a local database or serialization. Something like this and maybe this if you don't mind a vb.net example.
You need to create this method an extension method. It should be defined in static class:
public static class ObjectExtensions
{
public static bool ArePropertiesNotNull<T>(this T obj)
{
return typeof(T).GetProperties().All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
}

Compare Date is Greater than in C#

I'm trying to check if the passing variable date is greater than a static date which I have included in the code and currently trying to use the following code,
private String LastPayDate {
get {
string foo;
if(Parameters.TryGetValue("Last Pay Date", out foo))
return foo;
else
return null;
}
}
private Boolean IsLastPay() {
if (!string.IsNullOrEmpty(LastPayDate)) {
if(DateTime.Parse(Parameters.TryGetValue("Last Pay Date") >="24/05/2018")
return true;
else
return false;
}
return false;
}
however the only error I get is within below code section,
if(DateTime.Parse(Parameters.TryGetValue("Last Pay Date") > "24/05/2018")
can anyone help please ?
If you want to compare DateTimes, compare them, but not strings:
//TODO: what is the magic number (date) 24 May 2018?
private Boolean IsLastPay() {
if (Parameters.TryGetValue("Last Pay Date", out var dateSt))
if (DateTime.TryParse(dateSt, out var paramDate))
return paramDate >= new DateTime(2018, 5, 24);
else
return false; // DateTime.TryParse failed to parse the parameter
else
return false; // Parameters.TryGetValue failed to get the value
}
Thank you for respond. It did helped and I've managed to use below code and its working now, Much appreciate Help!
private Boolean IsLastPay()
{
if (!string.IsNullOrEmpty(LastPayDate))
{
string lpd;
}
if(Parameters.TryGetValue("Last Pay Date", out lpd))
{
if(DateTime.Parse(lpd) > new DateTime(2018,05,24))
return true;
else
return false;
}
}
return false;
}
Why not use the DateTime.Compare() method of DateTime class.
For this you need to have both the variables/objects of type DateTime.
string staticDate = "24/05/2018"; //dd-MM-yyyy
string inputDate = "14/08/20"; //dd-MM-yy
string greaterDate = CalculateGreaterDate(inputDate, staticDate); // 14/08/20 is greater
public static string CalculateGreaterDate(string iDate, string sDate)
{
// input date
string input = iDate;
var inputElements = input.Split('/');
int inputDay = Convert.ToInt32(inputElements[0]); //14
int inputMonth = Convert.ToInt32(inputElements[1]); //08
int inputYear = Convert.ToInt32(inputElements[2]); //20
// static date
string static = sDate;
var staticElements = static.Split('/');
int staticDay = Convert.ToInt32(staticElements[0]); //24
int staticMonth = Convert.ToInt32(staticElements[1]); //05
int staticYear = Convert.ToInt32(staticElements[2]); //2018
DateTime inputDate = new DateTime(inputYear, inputMonth, inputDay);
DateTime staticDate = new DateTime(staticYear, staticMonth, staticDay);
// DateTime.Compare(d1, d2) returns:
// > 0 : d1 is greater than d2
// = 0 : d1 & d2 are equal
// < 0 : d1 is smaller than d2
int result = DateTime.Compare(inputDate, staticDate);
if (result > 0)
return iDate + " is greater";
else if (result < 0)
return sDate + " is greater";
else if (result == 0)
return iDate + " is equal to " + sDate;
}

Are 3 or more times overlapping C#

I am trying to determine whether times ranges are overlapping on a CRUD page but am stuck.
I can get it working with two time ranges using the code below but I need it working for 3 as well.
public static bool IsOverLapping(ConfigureViewModel viewModel)
{
bool status = false;
var times = viewModel.Periods.OrderBy(x => x.StartTime.TimeOfDay).ToList();
for (var i = 0; i <= times.Count - 2; i++)
{
if (times[i].StartTime.TimeOfDay <= times[i + 1].EndTime.TimeOfDay)
{
if (times[i + 1].StartTime.TimeOfDay >= times[i].EndTime.TimeOfDay)
status = false;
else
return true;
}
else
return true;
}
return status;
}
The data comes in as DateTime values which is why I have only looked at the 'TimeOfDay' value. The image shows the layout of the CRUD page.
This is actually trickier than it seems, as you need to handle time periods that wrap across midnight.
Using some extension methods, you can make it straight forward.
First, determine if a time is between two others:
public static bool Between(this TimeSpan aTime, TimeSpan startTime, TimeSpan endTime) => (startTime <= endTime) ? (startTime < aTime && aTime < endTime)
: (startTime < aTime || aTime < endTime);
Then create a special version using the Period class for the range:
public static bool Between(this TimeSpan aTime, Period aPeriod) => aTime.Between(aPeriod.StartTime.TimeOfDay, aPeriod.EndTime.TimeOfDay);
Finally create a test for if one range overlaps a second range (note this is asymmetric):
public static bool Overlaps(this Period aPeriod, Period bPeriod) => aPeriod.StartTime.TimeOfDay.Between(bPeriod) || aPeriod.EndTime.TimeOfDay.Between(bPeriod);
Now go through all the ranges and check if any range overlaps another range:
public static bool IsOverLapping(this List<Period> periods) {
var periodCount = periods.Count;
for (int j1 = 0; j1 < periodCount; ++j1)
for (int j2 = 0; j2 < periodCount; ++j2)
if (j1 != j2 && periods[j1].Overlaps(periods[j2]))
return true;
return false;
}
Finally you can use the method in your ConfigureViewModel method:
public static bool IsOverLapping(ConfigureViewModel viewModel)
{
bool status = false;
var times = viewModel.Periods.OrderBy(x => x.StartTime.TimeOfDay).ToList();
return times.IsOverLapping();
}
I think it might be simpler than it sounds. If you have period1 and period2, they are NOT overlapping if period1.Start > period2.End or if period1.End < period2.Start. If neither of these are true, then we know that they are overlapping:
I made this a static method on the Period class:
public class Period
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public static bool AreOverlapping(Period first, Period second)
{
if (first == null || second == null) return false;
// These two conditions define "overlapping" and must be true
return first.StartTime <= second.EndTime &&
first.EndTime >= second.StartTime;
}
}
Then this should simplify the logic in your method that detects if there are any overlapping periods in a group:
public static bool DoAnyOverlap(List<Period> periods)
{
if (periods == null || periods.Count < 2) return false;
var ordered = periods.OrderBy(p => p.StartTime).ToList();
for (var i = 0; i < ordered.Count - 1; i++)
{
if (Period.AreOverlapping(ordered[i], ordered[i + 1])) return true;
}
return false;
}
If for some reason you cannot modify the Period class, the logic can easily be incorporated into the DoAnyOverlap method:
public static bool DoAnyOverlap(List<Period> periods)
{
if (periods == null || periods.Count < 2) return false;
var ordered = periods.Where(p => p != null).OrderBy(p => p.StartTime).ToList();
for (var i = 0; i < ordered.Count - 1; i++)
{
if (ordered[i].StartTime <= ordered[i + 1].EndTime &&
ordered[i].EndTime >= ordered[i + 1].StartTime)
{
return true;
}
}
return false;
}
Try this:
var periods = new[]
{
new { start = TimeSpan.Parse("10:00"), end = TimeSpan.Parse("14:00") },
new { start = TimeSpan.Parse("16:00"), end = TimeSpan.Parse("17:00") },
new { start = TimeSpan.Parse("13:00"), end = TimeSpan.Parse("15:00") },
};
bool overlapping =
Enumerable
.Range(0, periods.Length)
.SelectMany(i =>
Enumerable
.Range(i + 1, periods.Length - i - 1),
(i, j) => new { A = periods[i], B = periods[j] })
.Any(x => !(x.B.start >= x.A.end || x.B.end <= x.A.start));
It'll work with DateTime too.
Assuming ConfigureViewModel class looks like that:
class ConfigureViewModel
{
...
public List<Period> Periods { get; set; }
}
class Period
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
You can use Time Period Library for .NET:
PM> Install-Package TimePeriodLibrary.NET
And IsOverLapping mathod may look as simple as that:
public static bool IsOverLapping(ConfigureViewModel vm, int numberOfOverlaps)
{
var ranges = vm.Periods.Select(q => new TimeRange(q.StartTime, q.EndTime));
TimePeriodCollection periodCollection = new TimePeriodCollection(ranges);
TimePeriodIntersector<TimeRange> intersector = new TimePeriodIntersector<TimeRange>();
return intersector.IntersectPeriods(periodCollection).Count > numberOfOverlaps;
}

Print elements from a list in ascending order(date) whilst splitting the line by each day- C#

I am trying to print the following in ascending order of the date :
static void Main(string[] args)
{
string meter_id = "08002220";
string calc_constant = "0.1";
string interval = "00000100";
List<DateTime> readingDate = new List<DateTime>();
List<float> volume = new List<float>();
List<float> odometer = new List<float>();
var get_timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
try
{
TextReader textReader = File.OpenText(#"C:\Users\umar\Documents\data format\test.csv");
var csv = new CsvReader(textReader);
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
readingDate.Add(DateTime.Parse(csv["Reading Date"]));
volume.Add(float.Parse(csv["Total Volume"]) / 1000);
odometer.Add(float.Parse(csv["Odometer"]) / 1000);
}
readingDate.Sort();
var printCMREG = readingDate.Zip(odometer, (first, second) => new { first, second });
var printCM = readingDate.Zip(volume, (first, second) => new { first, second });
Console.Write($" MEPMD01, 20080501, EDDYIQ, INSWT:053000,,,{get_timestamp},,OK,W,CMREG,{calc_constant},{interval},");
foreach (var print in printCMREG)
{
if (print.first.Hour == 0)
{
Console.Write($"{print.first.ToString("yyyyMMddHHmm")},R0,{print.second},");
}
}
Console.WriteLine("\n");
Console.Write($" MEPMD01, 20080501, EDDYIQ, INSWT:053000,,,{get_timestamp},,OK,W,CM,{calc_constant},{interval},");
foreach (var print in printCM)
{
Console.Write($"{print.first.ToString("yyyyMMddHHmm")},R0,{print.second},");
}
}
catch(System.IO.IOException e)
{
Console.WriteLine(e);
}
}
I have written the above code, which prints the date and time equivalent of a meter reading. What I need at the moment is the ability to sort the dates at the bottom in 24 hour format.
Console.Write($" MEPMD01, 20080501, EDDYIQ, INSWT:053000,,,{get_timestamp},,OK,W,CM,{calc_constant},{interval},");
foreach (var print in printCM)
{
Console.Write($"{print.first.ToString("yyyyMMddHHmm")},R0,{print.second},");
}
As can be seen in this line, this prints all the dates together, however, I want to split it up in 24 intervals.
Replace this loop:
foreach (var print in printCM)
{
Console.Write($"print.first.ToString("yyyyMMddHHmm")},R0,print.second},");
}
With this:
DateTime currentDay = null;
foreach (var print in printCM)
{
if(currentDay == null)
{
currentDay = print.first.Date;
}
else if(currentDay != print.first.Date)
{
Console.WriteLine();
currentDay = print.first.Date;
}
Console.Write($"{print.first.ToString("yyyyMMddHHmm")},R0,{print.second},");
}
It will see if the prints are on the same date. If not it will insert a newline and then update the currentDay variable.
This assumes your sort used earlier in your code is in fact sorting the list.
It would be better if you created a class and updated the variables in there, something like this, than you could just run a foreach each loop on the print them out.
public class CSVData
{
public DateTime ReadingDate { get; set; }
public float Volume { get; set; }
public float Odometer { get; set; }
}

maximum and minimum value in list

I'm currently doing my current project and I had a problem. Here's what the project needs to do:
Find the maximum and the minimum temperature from a certain range of date. The range of the date will be inputted by the user.
So, I make a form as the main menu for inputting the items and finding the maximum and minimum value (both in the new form). I also make a class to store the items:
public class TempDate
{
public double Temp { get; set; }
public DateTime Date { get; set; }
}
In the first form, just call it FormAddData, from here items will be stored into the list using a textbox and here's the code:
private void buttonSubmit_Click(object sender, EventArgs e)
{
FormMenu formMenu = (FormMenu)this.Owner;
DateTime date = dateTimePickerDate.Value.Date;
double temp = double.Parse(textBoxTemp.Text);
TempDate tempDate = new TempDate();
tempDate.Date = date;
tempDate.Temp = temp;
formMenu.listOfTempDate.Add(tempDate);
listBoxInfo.Items.Add(date + "\t" + temp + "°C");
}
In the second form that called FormMaxMinRange. In this form, I use two DateTimePicker the first one for the starting date and the second for the ending date. From here I need to make a button that will select all the items from the range that I used from starting and ending date. Here's my code:
private void buttonMaxMin_Click(object sender, EventArgs e)
{
FormMenu formMenu = (FormMenu)this.Owner;
DateTime start = dateTimePickerStart.Value.Date;
DateTime end = dateTimePickerEnd.Value.Date;
int highest = 0;
double max = formMenu.listOfTempDate[0].Temp;
int lowest = 0;
double min = formMenu.listOfTempDate[0].Temp;
for (int i = 1; i < formMenu.listOfTempDate.Count; i++)
{
if (formMenu.listOfTempDate[i].Date >= start
&& formMenu.listOfTempDate[i].Date <= end)
{
if (formMenu.listOfTempDate[i].Temp > max)
{
highest = i;
max = formMenu.listOfTempDate[i].Temp;
}
if (formMenu.listOfTempDate[i].Temp < min)
{
lowest = i;
min = formMenu.listOfTempDate[i].Temp;
}
}
}
listBoxMaxMin.Items.Add("");
listBoxMaxMin.Items.Add("Lowest temp: " + min + ", on " + formMenu.listOfTempDate[lowest].Date);
listBoxMaxMin.Items.Add("Highest temp: " + max + ", on " + formMenu.listOfTempDate[highest].Date);
}
Here's the main form that i declared the class (which include the list):
public partial class FormMenu : Form
{
public List<TempDate> listOfTempDate = new List<TempDate>();
public FormMenu()
{
InitializeComponent();
}
private void fromCertainRangeToolStripMenuItem_Click(object sender, EventArgs e)
{
FormMaxMinRange formMaxMinRange = new FormMaxMinRange();
formMaxMinRange.Owner = this;
formMaxMinRange.ShowDialog();
}
}
But, the problem is, the minimum value was not selected inside the range of selection. Also I want the max and min value was printed in the listbox. Sorry for the long and weird question. I hope someone can understand what I means with this question to complete my project. Thank you.
See this code snippet.
You can use Linq to select the reduced list (with Start/Enddate) and order it by Temp. Now you can easy select the first (min) and the last (max) object.
List<TempDate> loTempDateList = new List<TempDate>()
{
new TempDate() {Date = DateTime.Now.AddDays(-10), Temp = 10.01 },
new TempDate() {Date = DateTime.Now.AddDays(-5), Temp = 20.01 },
new TempDate() {Date = DateTime.Now.AddDays(-3), Temp = 30.01 },
new TempDate() {Date = DateTime.Now, Temp = 40.01 }
};
DateTime ldStart = DateTime.Now.AddDays(-6);
DateTime ldEnd = DateTime.Now.AddDays(-1);
var loDateList = loTempDateList.Where(item => item.Date <= ldEnd && item.Date >= ldStart)
.OrderBy(item => item.Temp);
TempDate loMin = loDateList.First();
TempDate loMax = loDateList.Last();
Console.WriteLine("{0}: {1} with max temp", loMax.Date, loMax.Temp);
Console.WriteLine("{0}: {1} with min temp", loMin.Date, loMin.Temp);
Output (for today):
9/26/2017 3:17:09 PM: 30.01 with max temp
9/24/2017 3:17:09 PM: 20.01 with min temp
Update (with your variable names):
Copy this under DateTime end = dateTimePickerEnd.Value.Date;in your Form
var loDateList = listOfTempDate.Where(item => item.Date <= end && item.Date >= start)
.OrderBy(item => item.Temp);
TempDate loMin = loDateList.FirstOrDefault();
TempDate loMax = loDateList.LastOrDefault();
if (loMin != null && loMax != null)
{
listBoxMaxMin.Items.Add("");
listBoxMaxMin.Items.Add("Lowest temp: " + loMin.Temp + ", on " + loMin.Date);
listBoxMaxMin.Items.Add("Highest temp: " + loMax.Temp + ", on " + loMax.Date);
}
I would suggest you use Linq Max and Min methods.
// filter out only the dates in the range you need
var items = formMenu.listOfTempDateWhere(
item => ((TempDate)item).Date >= start && ((TempDate)item).Date <= end
);
// get the maximum value
var max = items.Max(item => item.Temp);
// get the minimum value
var min = items.Min(item => item.Temp);
Just remember to add using System.Linq on the top of your .cs file
try this online
If you don't like a LINQ approach (I never use LINQ, for some, possibly invalid reason, I think it's evil), you can override the List class and extend it with methods of your own.
public class TempDataList<T> : List<TempData>
{
public TempDataList() : base()
{
}
public TempDataList(IEnumerable<TempData> collection) : base(collection)
{
}
public TempData GetMaxTemp(DateTime startDate, DateTime endDate)
{
TempData highestTempData = null;
for (int i = 0; i < this.Count; i++)
{
if (this[i].Date >= startDate && this[i].Date <= endDate)
{
if (highestTempData == null || this[i].Temp > highestTempData.Temp)
{
highestTempData = this[i];
}
}
}
return highestTempData;
}
public TempData GetMinTemp(DateTime startDate, DateTime endDate)
{
TempData lowestTempData = null;
for (int i = 0; i < this.Count; i++)
{
if (this[i].Date >= startDate && this[i].Date <= endDate)
{
if (lowestTempData == null || this[i].Temp < lowestTempData.Temp)
{
lowestTempData = this[i];
}
}
}
return lowestTempData;
}
}
And fill the extended list and call the methods:
TempDataList<TempData> tempDataList = new TempDataList<TempData>();
tempDataList.Add(new TempData(10, DateTime.UtcNow));
tempDataList.Add(new TempData(20, DateTime.UtcNow));
tempDataList.Add(new TempData(15, DateTime.MinValue));
tempDataList.Add(new TempData(25, DateTime.MaxValue));
Console.WriteLine(tempDataList.GetMaxTemp(DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(1)).Temp);
Console.WriteLine(tempDataList.GetMinTemp(DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(1)).Temp);

Categories

Resources