0

我正在编写一个函数来增加原始计算数据的时间尺度,时间密度约为 2 分钟到 5 分钟(之后还有其他更大的尺度)。有超过 100k 个数据点保存在一个不按时间顺序排列的数组中。我正在寻找查询数组并在两个日期时间内查找数据的最快方法。在代码运行时,每个数据点只需要使用一次,但由于数据不按顺序读取,因此必须多次读取。我对如何做到这一点有几个想法:

只需查看数组中的所有时间值,检查它们是否在给定的两个日期时间内。这将强制代码在每个新时间点运行整个数组约 50k 次。

使用我的时间数据在数组中创建一个布尔值,如果该值已被使用,该值将变为真。这将在日期时间比较之前对已使用的点进行布尔检查,这应该更快。

将数组重新组织成顺序,我不确定根据日期时间这需要多长时间。它首先会大大增加导入数据所需的时间,但是它可以使扩展查询更快。关于重新排序数组与乱序运行它所花费的时间比率的任何想法?

欢迎任何其他建议。

如果人们觉得有必要,我会添加一些代码。提前致谢。

编辑:根据要求提供一些示例。

以下是数组的定义:

    Dim ScaleDate(0) As Date
    Dim ScaleData(0) As Double

我使用redim preserveSQL 将数据添加到其中。

这是从数组复制的日期时间点的示例。

(0) = #2/12/2012 12:01:36 AM#
4

1 回答 1

2

首先,正如 Tim Schmelter 建议的那样,我会使用 aList(Of T)而不是数组。它可能会更有效率,并且肯定会更容易使用。其次,我建议您定义自己的类型,该类型存储单个项目的所有数据,而不是将项目的每个属性存储在单独的列表中。这样做会使将来更容易修改,但也会更有效,因为您只需要调整一个列表而不是两个:

Public Class MyItem
    Public Property ScaleDate() As Date
        Get
            Return _scaleDate
        End Get
        Set(ByVal value As Date)
            _scaleDate = value
        End Set
    End Property
    Private _scaleDate As Date

    Public Property ScaleData() As Double
        Get
            Return _scaleData
        End Get
        Set(ByVal value As Double)
            _scaleData = value
        End Set
    End Property
    Private _scaleData As Double
End Class

Private _myItems As New List(Of MyItem)()

很难说哪个会更快,排序列表或搜索列表。这完全取决于它的大小、更改的频率以及您搜索它的频率。因此,我建议您尝试这两种选择,并亲自查看哪种方案在您的场景中效果更好。

对于排序,如果你有自己的类型,你可以简单地实现它IComparable(Of T),然后调用Sort列表中的方法:

Public Class MyItem
    Implements IComparable(Of MyItem)

    Public Property ScaleDate() As Date
        Get
            Return _scaleDate
        End Get
        Set(ByVal value As Date)
            _scaleDate = value
        End Set
    End Property
    Private _scaleDate As Date

    Public Property ScaleData() As Double
        Get
            Return _scaleData
        End Get
        Set(ByVal value As Double)
            _scaleData = value
        End Set
    End Property
    Private _scaleData As Double

    Public Function CompareTo(ByVal other As MyItem) As Integer Implements IComparable(Of MyItem).CompareTo
        Return ScaleDate.CompareTo(other.ScaleDate)
    End Function
End Class

Private _myItems As New List(Of MyItem)()

'To sort the list after it's been modified:
_myItems.Sort()

您只想在每次修改列表时对列表进行一次排序。您不想在每次搜索列表时对其进行排序。此外,对它本身进行排序并不会使从前到后的搜索速度更快,因此您需要实现一个快速搜索排序列表的 find 方法。例如,这些方面的东西应该起作用:

Private Function FindIndex(ByVal startDate As Date) As Integer
    FindIndex(startDate, 0, _myItems.Count - 1)
End Function

Private Function FindIndex(ByVal startDate As Date, ByVal startIndex As Integer, ByVal endIndex As Integer) As Integer
    If endIndex >= startIndex Then
        Dim midIndex As Integer = ((endIndex - startIndex) \ 2) + startIndex
        If _myItems(midIndex).ScaleDate < startDate Then
            Return FindIndex(startDate, midIndex, endIndex)
        Else
            Return FindIndex(startDate, startIndex, midIndex)
        End If
    Else
        Return startIndex
    End If
End Function

为了搜索未排序的列表,我只需在整个列表上从前到后循环,然后创建一个包含所有匹配项的新列表:

Dim matches As New List(Of MyItem)()
For Each item As MyItem In _myItems
    If (item.ScaleDate >= startDate) And (item.ScaleDate <= endDate) Then
        matches.Add(item)
    End If
Next

或者,如果这些项目上的日期大多是连续的,它们之间没有巨大的间隔,那么使用一个Dictionary(Of Date, List(Of MyItem))对象来存储你的项目列表可能是值得的。这将包含每个日期的单独项目列表,所有项目都存储在哈希表中。因此,要获取或设置特定日期的项目列表会非常快,但是要获取日期范围内所有项目的列表,您必须遍历日期范围内的每一天并获取列表那天从字典中,并将它们组合成一个匹配列表:

Dim _days As New Dictionary(Of Date, List(Of MyItem))()

'You'd need to loop through and add each item with code like this:
Private Sub AddItem(ByVal item As MyItem)
    Dim dayItems As List(Of MyItem) = Nothing
    _days.TryGetValue(item.ScaleDate, dayItems)
    If dayItems Is Nothing Then
        dayItems = New List(Of MyItem)()
        _days(item.ScaleDate) = dayItems
    End If
    dayItems.Add(item)
End Sub

'And then to find all the items in a date range, you could do something like this:
Private Function FindItemsInRange(ByVal startDate As Date, ByVal endDate As Date) As List(Of MyItem)
    Dim matches As New List(Of MyItem)()
    Dim i As Date = startDate
    While i <= endDate
        Dim dayItems As List(Of MyItem) = Nothing
        _days.TryGetValue(i, dayItems)
        If dayItems Is Nothing Then
            matches.AddRange(dayItems)
        End If
        i = i.AddDays(1)
    End While
    Return matches
End Function
于 2012-09-19T12:13:37.337 回答