Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Week of the year" Algorithm needs improvements

I have an algorithm which scans through data read from a .csv file(approx 3700 lines) and assess's which trading week of the year each entry is in by running a count++ for every Sunday of that year and assigning the count value as the trading week when the date falls within that week.

It's working but performance is lagging. It is the 3rd function running using Task.Factory.StartNew (I have also tried parallel.Invoke).

Results of timing tests.

before: 00:00:05.58

after: 00:00:23.27

UPDATE

Added break after each trading week is set. Time improved but still slow.

new time: 00:00:15.74

For our purposes the 1st week of the year is week 1(not 0) and is defined as from the first day of the year until the Sunday. If the first day of the year is a Sunday the length of week 1 is 1 day.

private void SetDefiniteWeeks()
        {
            string FileLoc = FilePath + Market + ".csv";
            string[] Data = File.ReadAllLines(FileLoc);
            var FileData = from D in Data
                           let DataSplit = D.Split(',')
                           select new
                           {
                               Date = DateTime.Parse(DataSplit[0]),
                               ClosingPrice = double.Parse(DataSplit[4])
                           };

            //assign each date to it's relevant week
            TradingWeek TW;
            List<TradingWeek> tradingWeek = new List<TradingWeek>();
            foreach (var pe in FileData)
            {
               // DateTime dt = pe.Date;
                int Year = pe.Date.Year;
                string End_of_Week = "Sunday";
                int WeekCount = 0;

                DateTime LoopDate_Begin = new DateTime(Year,1,1);
                DateTime LoopDate_End = new DateTime(Year,12,31);
                do
                {
                    if (LoopDate_Begin.DayOfWeek.ToString() == End_of_Week)
                    {
                        WeekCount++;
                        if (LoopDate_Begin.DayOfYear > pe.Date.DayOfYear && LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7))
                        {
                            TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
                            tradingWeek.Add(TW);
                            break;
                        }
                    }
                    LoopDate_Begin = LoopDate_Begin.AddDays(1);

                } while (LoopDate_Begin.Date.ToString() != LoopDate_End.Date.ToString());

            }

        }

Please help.

UPDATE

NEW TIME

00:00:06.686

A vast improvement. Thanks all for your help.

Revised code:

    CalendarWeekRule cw = CalendarWeekRule.FirstDay;
    var calendar = CultureInfo.CurrentCulture.Calendar;
    var trad_Week = (from pe in FileData
                        select new TradingWeek
                        {
                        Date = pe.Date,
                        Week = (calendar.GetWeekOfYear(pe.Date, cw,DayOfWeek.Sunday))
                        }).ToList();
like image 201
Chris Avatar asked Dec 17 '22 22:12

Chris


2 Answers

Im not sure if this is what you want but after reading the comments I got the feeling that this might work (?)

var calendar = CultureInfo.CurrentCulture.Calendar;
var tradingWeek = (from pe in FileData
                  select new TradingWeek
                  {
                    Date = pe.Date,
                    Week = calendar.GetWeekOfYear(pe.Date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
                  }).ToList();

Edit: Changed to CalendarWeekRule.FirstDay since it's (more?) what OP is looking for.

like image 199
Jesper Palm Avatar answered Jan 04 '23 17:01

Jesper Palm


Three quick thoughts:

  • Why are you only adding one day each time and checking to see if it's Sunday. Surely once you have found your first Sunday you can add seven days to find the next one?

  • If you order your pes by DateTime before you start then you don't need to restart at the beginning of the year for each one, you can pick up where you left off.

  • As Nicolas says, break after adding the trading week. No need to go through the rest of the year after you already know what the answer is.

I guess you'll end up with something like this (may or may not actually work, but should be close enough)

TradingWeek TW;
List<TradingWeek> tradingWeek = new List<TradingWeek>();
string End_of_Week = "Sunday";
var orderedData = FileData.OrderBy(x => x.Date)
DateTime LoopDate_Begin = new DateTime(orderedData[0].Date.Year,1,1);
int WeekCount = 1; 

while (LoopDate_Begin.DayOfWeek.ToString() != End_of_Week)
{
    LoopDate_Begin = LoopDate_Begin.AddDays(1);
}

foreach (var pe in orderedData)
{
    do
    {           
        if (LoopDate_Begin.DayOfYear > pe.Date.DayOfYear && LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7))
        {
            TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
            tradingWeek.Add(TW);
            break;
        }
        WeekCount++;
        LoopDate_Begin = LoopDate_Begin.AddDays(7);

    } while (true); //need to be careful here

}
like image 20
Martin Harris Avatar answered Jan 04 '23 16:01

Martin Harris