“一年中的一周”算法需要改进

时间:2010-07-28 16:32:55

标签: wpf algorithm c#-4.0

我有一个算法,它扫描从.csv文件中读取的数据(大约3700行),并通过在该年的每个星期日运行一个计数++并将计数值指定为每个条目,评估每个条目所在的交易周。交易周当日期在该周内。

它正在发挥作用,但性能却落后了。它是使用Task.Factory.StartNew运行的第三个函数(我也尝试过parallel.Invoke)。

时间测试的结果。

之前:00:00:05.58

之后:00:00:23.27

更新

设置每个交易周后添加休息时间。时间有所改善但仍然很慢。

新时间:00:00:15.74

对于我们的目的,一年中的第一周是第1周(不是0),并且定义为从一年的第一天到星期日。如果一年的第一天是星期日,则第1周的长度为1天。

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

            }

        }

请帮忙。

更新

新时间

00:00:06.686

一项巨大的改进。谢谢大家的帮助。

修订代码:

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

8 个答案:

答案 0 :(得分:4)

三个快速的想法:

  • 为什么你每次只增加一天并检查它是否是星期天。当你找到第一个星期天时,你可以增加七天来找到下一个星期日吗?

  • 如果你在开始之前按照DateTime订购你的pes,那么你不需要在每年的年初重新开始,你可以从你离开的地方继续。

  • 正如尼古拉斯所说,在加入交易周后突破。在你已经知道答案是什么之后,无需经历一年中的剩余时间。

我想你最终会得到这样的东西(可能或可能不会真正起作用,但应该足够接近)

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

}

答案 1 :(得分:4)

我不确定这是否是您想要的但是在阅读完评论后我觉得这可能有用(?)

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

编辑:改为CalendarWeekRule.FirstDay,因为它是(更多?)OP正在寻找的东西。

答案 2 :(得分:1)

如果我找到你,你不需要在添加TradingWeek后再查看

所以,你可以

break;

之后

tradingWeek.Add(TW);

然后你甚至可以省略

&& LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7)

条件,因为第一部分只会是真实的一次:为你想要的间隔。

答案 3 :(得分:1)

您甚至可以通过将自开始周以来的天数除以7来进行无环路方法 - 并进行一些清理工作;)

答案 4 :(得分:1)

你可以通过直接计算周数来完全摆脱do循环吗?类似于接受的答案here

答案 5 :(得分:1)

按照@ nicolas78的回复,这样的事情应该有效

int Year = pe.Date.Year;
DateTime Year_Begin = new DateTime(Year,1,1);
int Jan1DayOfWeek = Year_Begin.DayOfWeek;

foreach (var pe in FileData)
{
    int WeekCount = (pe.Date.DayOfYear - Jan1DayOfWeek) % 7 + 1;
    TradingWeek TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
    tradingWeek.Add(TW);
}

根据DayOfWeek和DayOfYear的计数方式,即0或1,以及mod操作的工作方式,您可能需要稍微调整WeekCount计算。

答案 6 :(得分:0)

您根本无需计算 - 只需快速计算即可。这假设一年开始的部分周是第1周,第2周从第一个星期一开始。

List<TradingWeek> tradingWeek = new List<TradingWeek>();
foreach (var pe in FileData)
{
    var date = pe.Date;
    while (date.DayOfWeek != DayOfWeek.Sunday)
        date = date.AddDays(1);
    var week = date.DayOfYear/7+1;
    var TW = new TradingWeek {Week = week, Date = pe.Date};
    tradingWeek.Add(TW);
}

答案 7 :(得分:0)

有一个内置功能可以根据.NET中的日期获取一年中的一周。下面显示了一个示例,但可能需要进行一些调整以适合您的业务场景:

System.Globalization.CultureInfo myCI = new System.Globalization.CultureInfo("en-US");

int week = myCI.Calendar.GetWeekOfYear(DateTime.Now.ToUniversalTime(), System.Globalization.CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Sunday);