VB.NET - 将一维数组插入到二维数组中

3

我正在开发一个优化算法,需要将一些数据(由算法生成)存储在名为matrix的二维数组中,其中第i行包含优化向量(i)的适应度分数和参数值。

Dim matrix(vectorCount() - 1, parameterCount()) As Double
Dim params(parameterCount() - 1) As Double

For i As Integer = 0 To vectorCount() - 1
    matrix(i, 0) = vectorScore(i)
    params = vectorValues(i)
    For j As Integer = 0 To params.Length - 1
        matrix(i, j+1) = params(j)
    Next
Next

vectorCount()函数返回向量的数量。
parameterCount()函数返回每个向量中参数的数量。
vectorScore(int vectorIndex)函数返回指定向量的适应度得分。
vectorValues(int vectorIndex)函数返回指定向量的参数值数组。

我的问题:
是否有更快(即更高效)的方法将params插入matrix中?

4个回答

4
如果您想要高效率,那么依靠“普通”数组无疑是最佳选择。与其他替代品(如Collections、List等)相比,它们之所以如此高效,是因为它们包含了所需的最少信息。如果您想要精致的函数来轻松/快速地排序信息或编写复杂的查询以检索数据,那么您不应该依赖于数组。
我总是依赖于像您编写的代码这样的代码,从未遇到速度问题(这真的很快)。我进行了快速的调查,确保没有其他选项,但没有找到任何选项。最接近的是Array.Copy,尽管它仅适用于数组具有相同维度(我个人仅使用1D数组时才使用它)。无论如何,我在有趣的链接中找到了关于Array.Copy()与循环性能在2D数组中的比较(它是在C#中的,但所有内容都适用于VB.NET)。
总结:您的代码非常快,不需要改进。如果有有效的替代方法(Array.Copy对于2D和1D均适用,但不存在),则结果性能仅会稍微好一点(仅适用于小数组大小)。

+1 个好答案!在我的情况下,循环 ì 可能会有高达 10-20 百万次迭代,而循环 j 最多只有 12-15 次迭代,这使得总共至少有 1.2 亿次迭代。即使在这些数字下,我的代码是否仍然是一个好的选择? - bluebox
@bluebox 谢谢。我猜你的答案也值得被知道(最近人们太担心简单编码和低效存储替代方案了)-> 立刻给它点赞。 - varocarbas
1
@bluebox,实际上根据这些数字,你的代码是唯一可接受的解决方案(即使在有工作的Array.Copy的不现实情况下)。正如您在提供的链接中所看到的,数组大小越大(迭代次数越多),循环性能就越好。 - varocarbas
@bluebox 我猜你知道创建太大的数组不是一个好主意(根本不是);所以我理解你正在考虑不同的数组或在不同的时刻执行迭代,但你没有把所有这些记录放在同一个数组中。 - varocarbas
谢谢你指出这个问题 - 老实说,我其实没有考虑过这个问题。这是我第一次处理这么大量的数据.. - bluebox
1
@bluebox 没问题。尽可能使用一维数组,当转移到二维数组时,保持第一维度在1000以下。这将取决于数组的数量和给定计算机的内存;这是一个最安全的建议。您需要进行性能测试并在预期条件下绘制实际限制。但这是完全不同的故事;我的答案很明确:这是最好的方法吗?是的。 :) - varocarbas

1
Function OneD2TwoD(ByVal xLen As Integer, ByVal yLen As Integer)
    ' (1) populate 1d array
    Dim TwoD(xLen, yLen) As Integer
    Dim OneD((xLen + 1) * (yLen + 1) - 1) As Integer
    For i As Integer = 0 To OneD.GetUpperBound(0)
        OneD(i) = i
    Next
    PrintValues(OneD, "|")
    Console.WriteLine()
    ' (2) Convert 1d array to 2d array/
    Dim z, Row(yLen) As Integer
    For x As Integer = 0 To xLen
        For y As Integer = 0 To yLen
            z = x * (yLen + 1) + y
            TwoD(x, y) = OneD(z)
            Row(y) = TwoD(x, y)
        Next
        PrintValues(Row, "|")
    Next
    Console.WriteLine()
    ' (3) Convert 2d array to 1d array/
    Erase OneD
    ReDim OneD((xLen + 1) * (yLen + 1) - 1)
    For x As Integer = 0 To xLen
        For y As Integer = 0 To yLen
            z = y + x * (yLen + 1)
            OneD(z) = TwoD(x, y)
        Next
    Next
    PrintValues(OneD, "|")
End Function

Public Sub PrintValues(ByVal myList As IEnumerable, ByVal mySeparator As Char)
    ' source: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.add(v=vs.110).aspx
    Dim obj As [Object]
    For Each obj In myList
        Console.Write("{0}{1}", mySeparator, obj)
    Next obj
    Console.WriteLine()
End Sub 'PrintValues

示例: OneD2TwoD(0, 10)

(1) 填充一维数组

|0|1|2|3|4|5|6|7|8|9|10

(2) 将一维数组转换为二维数组

|0|1|2|3|4|5|6|7|8|9|10

(3) 将二维数组转换为一维数组

|0|1|2|3|4|5|6|7|8|9|10

示例: OneD2TwoD(5, 0)

(1) 填充一维数组

|0|1|2|3|4|5

(2) 将一维数组转换为二维数组

|0

|1

|2

|3

|4

|5

(3) 将二维数组转换为一维数组

|0|1|2|3|4|5

示例: OneD2TwoD(2, 5)

(1) 填充1D数组

|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17

(2) 将1D数组转换为2D数组

| 0| 1| 2| 3| 4| 5

| 6| 7| 8| 9|10|11

|12|13|14|15|16|17

(3) 将2D数组转换为1D数组

|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17

感谢您的关注


请尽量避免只是把代码作为答案,而是尝试解释它的作用和原因。对于没有相关编程经验的人来说,您的代码可能不太明显。 - Frits

1

如果你想使用多个线程,可以使用并行for循环。

http://msdn.microsoft.com/en-us/library/dd460713.aspx

Dim matrix(vectorCount() - 1, parameterCount()) As Double
Dim params(parameterCount() - 1) As Double

Parallel.For(0, vectorCount() - 1, Sub(i)
                                      matrix(i, 0) = vectorScore(i)
                                      params = vectorValues(i)
                                      For j As Integer = 0 To params.Length - 1
                                          matrix(i, j+1) = params(j)
                                      Next
                                   End Sub)

1

这在很大程度上取决于数组的大小,for循环非常高效,但是对于非常大的数组,您可以通过array.copy或buffer.blockcopy看到改进。

Sub Main()

    Const ARR_SIZE_X As Integer = 9999999
    Const ARR_SIZE_y As Integer = 5
    Const DBL_SIZE As Integer = 8

    Dim watch As New Stopwatch

    Dim a1(ARR_SIZE_X) As Double
    Dim a2(ARR_SIZE_y, ARR_SIZE_X) As Double

    For x = 0 To ARR_SIZE_X
        a1(ARR_SIZE_X) = x
    Next

    watch.Start()

    For t = 0 To 10
        For y = 0 To ARR_SIZE_y
            For x = 0 To ARR_SIZE_X
                a2(y, x) = a1(x)
            Next
        Next
    Next

    watch.Stop()
    Console.WriteLine(watch.ElapsedTicks)

    watch.Reset()

    watch.Start()

    For t = 0 To 10
        For y = 0 To ARR_SIZE_y
            System.Buffer.BlockCopy(a1, 0, a2, (ARR_SIZE_X + 1) * DBL_SIZE * y, DBL_SIZE * ARR_SIZE_X)
        Next
    Next

    watch.Stop()
    Console.WriteLine(watch.ElapsedTicks)

    'For y = 0 To 4
    '    For x = 0 To 4
    '        Console.Write(a2(y, x))
    '    Next

    '    Console.WriteLine()
    'Next

    Console.ReadLine()

End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接