Get a list of dates responding to rules - c#

I have a list of dates like:
21/12/2019
22/12/2019
22/12/2019
24/12/2019
26/12/2019
26/12/2019
27/12/2019
I have the rule model defined as:
public class Timing
{
public int PeriodNbMinutes { get; set; }
public int NbTimes { get; set; }
public bool IsConsecutive { get; set; }
public int Multiplicity { get; set; }
}
Now I have the rule like: I want to find all dates where:
Dates which appears 3 times in 2 days and for twice times
So I should get two groups (I don't want to reuse dates already in a group):
First
1st: 21/12/2019 - 22/12/2019 - 22/12/2019
Second
2nd: 26/12/2019 - 26/12/2019 - 27/12/2019
I then have my rule like this:
this.PeriodMinutes = 2680;
this.NbTimes = 2;
this.Multiplicity = 2;
this.IsConsecutive=true;
Edited
public int PeriodNbMinutes { get; set; }
public int NbTimes { get; set; }
public bool IsConsecutive { get; set; }
public int Multiplicity { get; set; }
internal bool Test(List<DateTime> metrics)
{
bool res = false;
int times = 0;
int multiple=0;
TimeSpan ts = new TimeSpan(0, PeriodNbMinutes, 0);
for (int i = 0; i < metrics.Count; i++)
{
var dates = metrics.Skip(i);
var selectedDts = metrics.Zip(dates, (dtFirst, dtNext) => (dtNext - dtFirst).Ticks < ts.Ticks);
if (selectedDts.Count() > 0)
{
res = true;
times++;
if (times == Multiplicity)
{
multiple++;
if (multiple == Multiplicity)
return true;
// Consecutive???
}
else res = false;
}
else
{
res = false;
times = 0;
}
}
return res;
}
How can I find these groups with Linq? I tried with TimeSpan but can't get it to work.
Additionally, In the two groups selected I need to know if they are consecutive or not.
I tried a lot of different solutions but nothing good. How can I do it simply?
Thanks,

Related

i have a problem with my adaptive moving average trading system

I created a trading system with an adaptive moving average on the average true range but the program reports this error to me
the modifier public is not valid for this item
at line 21 of the code
public int avgTrueRange.value1 { get; set; }
I tried to change public but it always reports this error.
this is the code :
public class MediaMobileAdattiva : SignalObject
{
public MediaMobileAdattiva(object _ctx): base(_ctx)
{
Range = 14;
FirstLength = 10;
AvgTrueRange.value1 = 1;
}
private IOrderMarket buy_order;
public int Range { get; set; }
public double FirstLength { get; set; }
public int AvgTrueRange.value1 { get; set; }
private double FirstAverage()
{
if (AverageTrueRange < AvgTrueRange.value1)
return FirstLength;
}
protected override void Create()
{
// create variable objects, function objects, order objects
buy_order = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.Buy));
}
protected override void StartCalc()
{
// assign inputs
}
protected override void CalcBar()
{
// strategy logic
if (Bars.CurrentBar > 1)
{
switch (FirstAverage)
{
case FirstLength:
return 1;
}
}
if (Bars.CurrentBar > 1 && Bars.Close.CrossesOver(FirstAverage, ExecInfo.MaxBarsBack)
{
switch (FirstLength)
{
case 1:
buy_order.Send(Bars.Close[0]);
}
}
}
}
What you need is to make a struct for AvgTrueRange:
public struct Range
{
public int value1 {get; set;}
}
and change:
public int AvgTrueRange.value1 { get; set; }
to
public Range AvgTrueRange { get; set; }
Your code still won't compile btw but I don't really understand what you are trying to do in this line:
if (AverageTrueRange < AvgTrueRange.value1)
Also, change:
switch (FirstAverage)
{
case FirstLength:
return 1;
}
to
var avg = FirstAverage();
int? result = avg switch
{
var avg when avg == FirstLength => 1,
_ => null
};
if (result.HasValue) return result.Value;
as cases can only be constant values.

C# appending values to string[] doesn't work

So I'm trying to append values to a list (in Json []), that's empty or has items in it. So I check wether the list in the object has items in it or not, if the item doesn't exist, then it creates a new item, if it exists, it rewrites it's value. Here is the code:
if (e.Key == Key.Enter)
{
// When the user pressed enter, do action
Team selected_team = teams.Where(t => t.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
if (selected_team != null)
{
// when the team number is given, go try and find the data of them
Results team_results = results.Where(r => r.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
int index = (Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1);
// Check if the item in the list exists
if (index < team_results.results[inp_tour_part.SelectedIndex].gtks.Length && team_results.results[inp_tour_part.SelectedIndex].gtks[index] != null)
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = gtk_input.Text; // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = "00:00"; // Give the default value
}
}
else
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks.Append(gtk_input.Text); // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks.Append("00:00"); // Give the default value
}
}
SaveResults(results);
// Move to the next UI element
MoveToNextUIElement(e);
}
else
{
MessageBox.Show("Something went somewhere wrong.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
Now, it works fine to rewrite the items, but when the list is empty (default) or when the item doesn't exist, and it needs to add/append the new value, it doesn't crahs and doesn't throw any error... Also it doesn't add the value to my json, now when I initialize the new object for this, it looks like the following:
team_results = new Results()
{
team_number = selected_team.team_number,
results = new Result[2] { new Result{ }, new Result { } } // Fixed length of array for the results. TODO: Needs fix.
};
And the model looks like this:
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public string[] gtks { get; set; }
}
}
Now I just need a list of strings in my json, but I don't have any clue on how to achieve this...
If you MUST, you can resize an array using Array.Resize() method. Please see documentation here.
int[] array = new int[] { 1, 2, 3 };
Array.Resize(ref array, 5);
array[3] = 4;
array[4] = 5;
But it is strongly advised the use of List<T> instead of arrays. After all List<T> uses arrays behind the scenes so you get all the functionality of an array minus most of the cons.
You can use List instead. Thus you don't need to know the array size when instantiating the list.
Why not alter your models so they implement List instead of array. In the constructor of each model just initialize the empty list (or other action depending on your situation)
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public List<Result> results { get; set; }
public Results() {
results = new List<Result>();
}
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public List<string> gtks { get; set; }
public Result() {
gtks = new List<string>();
}
}
}
Then when you have your models you can add to each list like the following:
Results r = new Results();
r.results.Add(new Result()); // or other `result` object here
Result r = new Result();
r.gtks.Add("My String"); // or other `string` here
I think you can implement a method which would create a new array based on original one. Then, you would be able to override that original array with the resulted one (returned by that new method).
The example code would be the following:
var test = new string[1] { "Test string 1" };
test = AddItemToArray(test, "Test string 2");
private static string[] AddItemToArray(string[] original, string item)
{
var result = new string[original.Length + 1];
for (int i = 0; i < original.Length; i++)
{
result[i] = original[i];
}
result[result.Length - 1] = item;
return result;
}

How do I best handle data in my application

Working on a C# application for Payroll. As a warning, I'm very new to all this, just been chucked in to it and enjoying it but it's a lot to absorb in a short amount of time. I'm currently learning about LINQ and classes. I'm grabbing invoice lines out of our account SQL server and paying personnel based on sales and some situations that can be determined from the data. See the sample below:
Ord_Inv_No Delivery_Date Trmnl_Key TrmnlGrp_Key
INV-00059754 2016-05-02 07:00:00 23 3
INV-00059839 2016-05-02 16:01:00 56 3
This is a very small portion of the data but it gives the gist of what I want to analyze. I have a class as shown below:
class SalesItem
{
public string DriverName { get; set; }
public DriverData DriverData { get; set; }
public int TerminalKey { get; set; }
public int TerminalGroupKey { get; set; }
public string DeliveryDate { get; set; }
public string CustomerLocation { get; set; }
public int? CustomerLocationKey { get; set; }
public bool? IsCredited { get; set; }
public string InvoiceNumber { get; set; }
public string TermianlGroupDesc { get; set; }
public SalesItem(string driverName, int terminalKey, int terminalGroupKey, string deliveryDate,
string customerLocation, int? customerLocationKey, bool? isCredited, string invoiceNumber, string terminalGroupDesc)
{
this.DriverName = driverName;
this.TerminalKey = terminalKey;
this.TerminalGroupKey = terminalGroupKey;
this.DeliveryDate = deliveryDate;
this.CustomerLocation = customerLocation;
this.CustomerLocationKey = customerLocationKey;
this.IsCredited = isCredited;
this.InvoiceNumber = invoiceNumber;
this.TermianlGroupDesc = terminalGroupDesc;
}
I'm trying to implement a way I can 1. store each SalesItem (each row) as a Collection for lack of a better word. I want to iterate through the collection of SalesItem and find out a few things, like when an Invoice row shows up twice with a different Trmnl_Key and two different Ord_Inv_No that have the exact same Date as one another and return the greatest rate of pay for the two. I had written some logic for this that was manipulating a DataTable that I was grabbing through SQLConnection/Command/Reader/Etc but all of this was very slow and cumbersome when dealing with a week of data and I couldn't get the comparison to work reliably. Further down the line, these rows would be flagged in a DataGrid in WPF for human verification of their pay in case of something funky coming in from the accounting software.
Right now, I'm trying to save the collection as shown below (which is just the current iteration, I have several days worth of trying that's failed.)
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData();
driver.SetDriverData(driverKey);
int years = driver.ServiceYears;
List<SalesItem> items = (from o in transportationDb._Payroll_Orders
where o.Ord_Driver_Key == driverKey &&
o.Delivery_Date >= new DateTime(2016, 5, 2) && o.Delivery_Date <= new DateTime(2016, 5, 8)
select new SalesItem(
o.Driver_Name,
o.Trmnl_Key,
o.TrmnlGrp_Key,
o.Delivery_Date.ToString(),
o.CustLoc_Description,
o.Ord_CustLoc_Key,
o.Credits, o.Ord_Inv_No, o.TrmnlGrp_Description )).ToList();
dataGrid.ItemsSource = items;
}
Any wisdom or direction would be much appreciated
Granted, this isn't much different than what you had, but try this and see if it works for you:
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData(); //What's this for?
driver.SetDriverData(driverKey); //What's this for?
int years = driver.ServiceYears; //What's this for?
var startDate=new DateTime(2016, 5, 2);
var endDate=new DateTime(2016, 5, 8);
var items = transportationDb._Payroll_Orders
.Where(o=>o.Ord_Driver_Key == driverKey)
.Where(o=>o.Delivery_Date >= startDate && o.Delivery_Date <= endDate)
.Select(o=>new SalesItem {
DriverName=o.Driver_Name,
...
});
dataGrid.ItemsSource = items;
}
If your Orders table has an index on Ord_Driver_key and Delivery_Date, then this query should be pretty quick.
I hope this helps in some way. I'm not too sure of what you're trying to achieve. A save function could look something like the following, but I don't know exactly what kind of connection you're using. Note that I'm checking to make sure the record doesn't exist already.
private void Save(SalesItem item)
{
if(!transportationDb._Payroll_Orders.Any(p => p.Ord_Inv_No == item.InvoiceNumber))
{
transportationDb._Payroll_Orders.Add(item.PayrollOrder);
transportationDb.SaveChanges();
}
else
{
// Already exists
}
}
Update your class to however you'd like, but I'd do it this way from the limited knowledge of what your object is suppose to look like.
class SalesItem
{
public SalesItem(_Payroll_Orders po == null, DriverData dd == null)
{
this._Payroll_Order = po != null ? po : new _Payroll_Orders();
this.DriverData = dd != null ? dd : new DriverData();
}
private _Payroll_Orders _Payroll_Order { get; set; }
public _Payroll_Orders PayrollOrder
{
get { return _Payroll_Order; }
set { _Payroll_Order = value; }
}
public string DriverName
{
get { return _Payroll_Order.Driver_Name; }
set { _Payroll_Order.Driver_Name= value; }
}
public DriverData DriverData { get; set; }
public int TerminalKey
{
get { return _Payroll_Order.Trmnl_Key; }
set { _Payroll_Order.Trmnl_Key= value; }
}
public int TerminalGroupKey
{
get { return _Payroll_Order.TrmnlGrp_Key; }
set { _Payroll_Order.TrmnlGrp_Key= value; }
}
public DateTime DeliveryDate
{
get { return _Payroll_Order.Delivery_Date; }
set { _Payroll_Order.Delivery_Date= value; }
}
public string CustomerLocation
{
get { return _Payroll_Order.CustLoc_Description; }
set { _Payroll_Order.CustLoc_Description = value; }
}
public int? CustomerLocationKey
{
get { return _Payroll_Order.Ord_CustLoc_Key; }
set { _Payroll_Order.Ord_CustLoc_Key = value; }
}
public bool? IsCredited
{
get { return _Payroll_Order.Credits; }
set { _Payroll_Order.Credits = value; }
}
public string InvoiceNumber
{
get { return _Payroll_Order.Ord_Inv_No; }
set { _Payroll_Order.Ord_Inv_No = value; }
}
public string TermianlGroupDesc
{
get { return _Payroll_Order.TrmnlGrp_Description; }
set { _Payroll_Order.TrmnlGrp_Description = value; }
}
}
then you can change your function here so you only have to select 'new SalesItem(o, driver)':
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData();
driver.SetDriverData(driverKey);
int years = driver.ServiceYears;
List<SalesItem> items = (from o in transportationDb._Payroll_Orders
where o.Ord_Driver_Key == driverKey &&
o.Delivery_Date >= new DateTime(2016, 5, 2) &&
o.Delivery_Date <= new DateTime(2016, 5, 8)
select new SalesItem(o, driver)).ToList();
dataGrid.ItemsSource = items;
}

Set max count in for statement

I have a model with a nested collection:
public class SomeClass
{
public SomeClass()
{
this.OtherPart = new HashSet<OtherPart>();
}
[Key]
public int SomeClassId { get; set; }
public string SomeData { get; set; }
public string SomeOtherData { get; set; }
public virtual ICollection<OtherPart> OtherParts { get; set; }
public void CreateOthers(int count = 1)
{
for (int i = 0; i < count; i++)
{
OtherParts.Add(new OtherPart());
}
}
}
with this Controller action:
public ActionResult Create()
{
var abc = new SomeClass();
abc.CreateOthers();
return View(abc);
}
and it works perfectly. The problem I now have is that for my use case i need to set a maximum number of items to create ( in this case 5).
I have tried the following modification in the void above, but it is ignored:
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && count < max; i++)
{
OtherParts.Add(new OtherPart());
}
}
Any suggestions on how to effectively limit the max number of items added to the nested collection?
Thanks!
You probably need a custom validator, similar to this:
public class MaxItemsAttribute : ValidationAttribute
{
private readonly int _max;
public MaxItemsAttribute(int max) {
_max = max;
}
public override bool IsValid(object value) {
var list = value as IList;
if (list == null)
return false;
if (list.Count > _max)
return false;
return true;
}
}
In your model code, just do this:
[MaxItems(5)]
public virtual ICollection<OtherPart> OtherParts { get; set; }
Change to i < max
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && i < max; i++)
{
OtherParts.Add(new OtherPart());
}

ordering generic list by size property

Hi I have had to use interfaces before but ive been told i need to implement icomparable in this instance. see below:
internal class doorItem : IComparable
{
public int CompareTo(doorItem other)
{
// The temperature comparison depends on the comparison of the
// the underlying Double values. Because the CompareTo method is
// strongly typed, it is not necessary to test for the correct
// object type.
return GetNumber(productSize).CompareTo(GetNumber(other.productSize));
}
public string variations { get; set; }
public double pricerange { get; set; }
public string viewDetailsLink { get; set; }
public string height { get; set; }
public string width { get; set; }
public string productSize { get; set; }
public string productImage { get; set; }
public int countItemsOnSale { get; set; }
public string optionFor35Product { get; set; }
private int GetNumber(string str)
{
//this method gets the int out of the string
int length = str.Length;
string output = String.Empty;
int test = 0;
bool err = false;
for (int i = 0; i <= length; i++)
{
try
{
test = Convert.ToInt32(str.Substring(i, 1));
}
catch
{
err = true;
}
if (!err)
output += str.Substring(i, 1);
else
break;
}
return Convert.ToInt32(output);
}
}
above is the class i have created, door sizes are returned like this: 4dr, 5dr, 6dr etc.. then the getnumber method gets the int out of the string.
i have a generic list in of my custom class in the main method like this:
List<doorItem> d = new List<doorItem>();
i cant work out how to order this list by door size.... PLEASE HELP
It's easiest to do this using LINQ. Then you don't even need to implement IComparable.
var sortedList = doorList.OrderBy( d => d.GetNumber(d.productSize ).ToList();
And make GetNumber public inside the doorItem class.
I don't know if performance is important, but that method for getting the number is pretty horrible, exceptions should only be used in exceptional circumstances! Suggest something like this
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (Char.IsNumber(c))
{
sb.append(c);
}
}
return Convert.ToInt32(sb.ToString());
For sorting you can do what stecya has suggested, or you could convert this method to a property and sort directly.
public int Size
{
get
{
return GetNumber(this.productSize);
}
}
...
d.OrderBy(x=>x.Size);

Categories

Resources