首页 > 解决方案 > C# 提高数组查找循环性能

问题描述

我有一个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(2'592'000) 中的数据量,该函数需要 40 秒!对于像 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}

将 tempbuffer 值转换为 AODate 很重要,因为 tempbuffer 数组中的数据显示在 mschart 中。

有没有办法改进我的代码,让我有更好的性能?

标签: c#arrayswinformsperformanceloops

解决方案


Array.Exists() 和 Array.Find() 是 O(N) 操作,您正在执行它们 x M (240) 次。

尝试 LINQ Join 代替:

DataPoint[] dataPoints; // your "file" variable
var seekedTimestamps = Enumerable.Range(0, 240).Select(i => unixTimestamp - i);
var matchingDataPoints = dataPoints.Join(seekedTimestamps, dp => dp.XValue, sts => sts, (dp, sts) => dp);
var missingTimestamps = seekedTimestamps.Except(matchingDataPoints.Select(mdp => mdp.XValue));
// do your logic with found and missing here
// ...

LINQ Join 使用散列(在选定的“键”上)并且接近 O(n)

或者,假设输入中的时间戳是唯一的,并且您计划对输入执行多个操作,请构造一个Dictionary<int (Timestamp), DataPoint>(昂贵的),这将为您提供 O(1) 检索所需数据点:var dataPoint = dict[wantedTimestamp];


推荐阅读