为了账号安全,请及时绑定邮箱和手机立即绑定

C# 提高数组查找循环性能

C# 提高数组查找循环性能

C#
炎炎设计 2021-09-19 16:20:36
我有一个Datapoint[] file = new Datapoint[2592000]数组。这个数组充满了时间戳和随机值。创建它们需要花费我 2 秒的时间。但是在另一个函数中,prepareData();我正在为另一个 Array 准备 240 个值TempBuffer。在prepareData()函数中,我正在搜索file数组中的匹配值。如果我找不到任何我取时间戳并将值设置为 0 否则我取找到的值 + 相同的时间戳。该函数如下所示:public void prepareData(){      stopWatch.Reset();    stopWatch.Start();    Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;    for (double i = unixTimestamp; unixTimestamp - 240 < i; i--)    {        bool exists = true;        if (exists != (Array.Exists(file, element => element.XValue == i)))        {            TempBuffer = TempBuffer.Skip(1).Concat(new DataPoint[] { new DataPoint(UnixTODateTime(i).ToOADate(), 0) }).ToArray();        }        else        {            DataPoint point = Array.Find(file, element => element.XValue == i);            TempBuffer = TempBuffer.Skip(1).Concat(new DataPoint[] { new DataPoint(UnixTODateTime(i).ToOADate(), point.YValues) }).ToArray();        }    }    stopWatch.Stop();    TimeSpan ts = stopWatch.Elapsed;}现在的问题是file函数需要 40 秒的(2'592'000) 中的数据量!对于 10'000 等较小的数量,这不是问题,并且可以正常快速地工作。但是一旦我将file大小设置为我喜欢的 2'592'000 点,CPU 就会被推到 99% 的性能并且该功能需要的时间太长。TempBuffer 样本值:X = UnixTimeStamp 转换为 DateTime 和 DateTime 转换为 AODate{X=43285.611087963, Y=23}文件样本值:X = Unixtimestamp{X=1530698090, Y=24}将临时缓冲区值转换为 AODate 很重要,因为临时缓冲区数组内的数据显示在 mschart 中。有没有办法改进我的代码,以便我获得更好的性能?
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

这是您的任务最高效的方式(这只是一个模板,而不是最终代码):


public void prepareData()

{

    // it will be initialized with null values

    var tempbuffer = new DataPoint[240];


    var timestamp = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;

    var oldest = timestamp - 240 + 1;


    // fill tempbuffer with existing DataPoints

    for (int i = 0; i < file.Length; i++)

    {

        if (file[i].XValue <= timestamp && file[i].XValue > timestamp - 240)

        {

            tempbuffer[file[i].XValue - oldest] = new DataPoint(file[i].XValue, file[i].YValues);

        }

    }


    // fill null values in tempbuffer with 'empty' DataPoints

    for (int i = 0; i < tempbuffer.Length; i++)

    {

        tempbuffer[i] = tempbuffer[i] ?? new DataPoint(oldest + i, 0);

    }

}

我有大约 10 毫秒


从评论更新:


如果您想获取多个DataPoint's并使用某个函数(例如平均值)获得结果,则:


public void prepareData()

{

    // use array of lists of YValues

    var tempbuffer = new List<double>[240];


    // initialize it

    for (int i = 0; i < tempbuffer.Length; i++)

    {

        tempbuffer[i] = new List<double>(); //set capacity for better performance

    }


    var timestamp = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;

    var oldest = timestamp - 240 + 1;


    // fill tempbuffer with existing DataPoint's YValues

    for (int i = 0; i < file.Length; i++)

    {

        if (file[i].XValue <= timestamp && file[i].XValue > timestamp - 240)

        {

            tempbuffer[file[i].XValue - oldest].Add(file[i].YValues);

        }

    }


    // get result

    var result = new DataPoint[tempbuffer.Length];

    for (int i = 0; i < result.Length; i++)

    {

        result[i] = new DataPoint(oldest + i, tempbuffer[i].Count == 0 ? 0 : tempbuffer[i].Average());

    }

}


查看完整回答
反对 回复 2021-09-19
?
米脂

TA贡献1836条经验 获得超3个赞

您还没有向我们提供您代码的完整图片。理想情况下,我希望示例数据和完整的类定义。但是考虑到可用的限制信息,我认为您会发现这样的工作:


public void prepareData()

    Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;


    var map = file.ToLookup(x => x.XValue);


    TempBuffer =

        Enumerable

            .Range(0, 240)

            .Select(x => unixTimestamp - x)

            .SelectMany(x =>

                map[x]

                    .Concat(new DataPoint(UnixTODateTime(x).ToOADate(), 0)).Take(1))

            .ToArray();

}


查看完整回答
反对 回复 2021-09-19
  • 3 回答
  • 0 关注
  • 318 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信