查询vb数组在两个边界内的日期时间的最快方法

时间:2012-09-19 08:17:33

标签: vb.net visual-studio visual-studio-2005

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

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

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

将数组重组为顺序,我不确定根据日期时间需要多长时间。它会大大增加首先导入数据所需的时间,但是它可以使缩放查询更快。是否有任何想法模糊地重新排序数组所需的时间与无序运行相比?

欢迎任何其他建议。

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

编辑:请求的几个例子。

以下是数组的定义:

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

我使用redim preserve,因为数据通过SQL添加到它们中。

以下是从数组中复制的日期时间点的示例。

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

1 个答案:

答案 0 :(得分:2)

首先,正如Tim Schmelter建议的那样,我会使用List(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()

每次修改时,您只希望对列表进行排序。每次搜索列表时都不希望对其进行排序。此外,对其进行排序和单独进行排序并不能更快地进行前后搜索,因此您需要实现一种快速搜索排序列表的查找方法。例如,沿着这些方向的东西应该有效:

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