【问题标题】:Fastest way to add an Item to an Array将项目添加到数组的最快方法
【发布时间】:2013-08-07 07:57:13
【问题描述】:

向现有数组添加新项目的最快方法是什么?

Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4

(我已经知道,在处理动态项目列表时,您应该使用ListArrayList 或类似的IEnumerables。但是如果您坚持使用使用数组的遗留代码该怎么办?)

到目前为止我已经尝试过:

' A) converting to List, add item and convert back
Dim list As List(Of Integer)(arr)
list.Add(newItem)
arr = list.ToArray()
' --> duration for adding 100.000 items: 33270 msec

' B) redim array and add item
ReDim Preserve arr(arr.Length)
arr(arr.Length - 1) = newItem
' --> duration for adding 100.000 items: 9237 msec

' C) using Array.Resize
Array.Resize(arr, arr.Length + 1)
arr(arr.Length - 1) = newItem
' --> duration for adding 100.000 items: 1 msec
' --> duration for adding 100.000.000 items: 1168 msec

A) 似乎很慢,因为每次添加一个项目时都会完成整个数组的两次转换。 B) 似乎更快,但在ReDim Preserve 期间仍然复制了一次数组。 C) 在这一点上似乎是最快的。有没有更好的?

【问题讨论】:

  • 恕我直言,我认为您是在将苹果与芒果进行比较:没有人不会使用您的第一个替代品。列表的优点之一是您可以多快地向其中添加新项目(如果您不转换为数组,只需添加项目,您会发现它比任何其他替代方法都快得多):如果您只对快速添加项目感兴趣,请使用列表(根本不依赖数组)。列表还允许比数组允许的更多选项来检查/索引其项目。但除此之外,在纯粹的性能方面(例如在循环内),它们要差得多......
  • 总结:在最好的情况下使用数组和列表。尽管 VB.NET 允许重新设置维度,但这并不是数组所期望的传递方式:数组在固定大小的条件下提供最佳性能,只是在其元素内反复迭代。另一方面,列表意味着较少迭代的处理:较少的元素数量、维度的定期变化、访问元素的花哨查询等。所有这些都是数组不太擅长的功能。因此,用于在固定大小条件下执行性能的数组;用于更改条件的列表。
  • PS:列表的内存效率也较低。
  • 感谢您的 cmets。像这样构建测试的原因是我想要一个Extension 方法来将项目添加到Array。这样编码需要更少的行:-)
  • 好吧...如果在您的特定条件下它为您提供了最好的结果,那就去做吧;但是,从理论的角度来看,这没有任何意义:您正在将列表的明确的快速项目添加功能转换为非常缓慢的添加。另一方面,少一行代码会让你振作起来;)

标签: arrays vb.net dynamic-arrays


【解决方案1】:

案例 C) 是最快的。将此作为扩展:

Public Module MyExtensions
    <Extension()> _
    Public Sub Add(Of T)(ByRef arr As T(), item As T)
        Array.Resize(arr, arr.Length + 1)
        arr(arr.Length - 1) = item
    End Sub
End Module

用法:

Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4
arr.Add(newItem)

' --> duration for adding 100.000 items: 1 msec
' --> duration for adding 100.000.000 items: 1168 msec

【讨论】:

  • 应该是 Array.Resize(arr,arr.Length+1) 我试过了。
  • 对于那些不知道下一步的人,只需添加新的模块文件并将@jor 代码(我的小黑,支持'nothing'数组)放在下面。 +---- 已编辑,代码混乱。去下面看看我的答案。
  • 我是一名长期的 Python 用户,正在使用 VB 进行概念验证项目。当我发现 VB 不支持将内容动态添加到数组中时,我偶然发现了您的解决方案,但是当我将您的代码放入模块时,Visual Studio 会在&lt;extension()&gt; 下划线并报告“System. Runtime.CompilerServices.ExtensionAttribute 在此上下文中不可访问,因为它是“朋友””我很困惑,因为子是公共的,而模块是公共的。对我正在做的事情有什么想法吗?
  • 添加导入 System.Runtime.CompilerServices 以使用扩展
  • 请记住,ExtensionAttribute 仅在 .NET Framework 3.5+ 中可用
【解决方案2】:
Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4
ReDim Preserve arr (3)
arr(3)=newItem

更多信息Redim

【讨论】:

  • 从技术上讲,你应该写:ReDim Preserve arr(3),否则你就是把数组超维了1。我个人不太在意这个(我超维数组几乎每次都加一个),但我想这将是一个更合适的答案。
  • 数组已经初始化为 3 个项目,他们想再添加一个项目,所以大小应该是 4 不是吗?
  • 是的,但是 ReDim Preserve arr (4) 并不表示大小为 4,而是表示最高索引为 4,即大小为 5。如上所述,我不应该在教这方面我一直在做你做的事,但从理论上讲,是不正确的。
  • 你是对的。我已经确定了我的答案。这是了解太多编程语言的不好的一面:-)
  • 没问题。这是我们都犯的典型错误。 C# 和 VB 有很多共同点,这些细节很容易被忽视。
【解决方案3】:

对于那些不知道下一步做什么的人,只需添加新的模块文件并将@jor 代码(我的小黑客,支持'nothing'数组)放在下面。

Module ArrayExtension
    <Extension()> _
    Public Sub Add(Of T)(ByRef arr As T(), item As T)
        If arr IsNot Nothing Then
            Array.Resize(arr, arr.Length + 1)
            arr(arr.Length - 1) = item
        Else
            ReDim arr(0)
            arr(0) = item
        End If

    End Sub
End Module

【讨论】:

    【解决方案4】:

    不是很干净,但它可以工作:)

    Dim arr As Integer() = {1, 2, 3}
    Dim newItem As Integer = 4
    
    arr = arr.Concat({newItem}).ToArray
    

    【讨论】:

      【解决方案5】:

      这取决于您插入或阅读的频率。如果需要,您可以将数组增加不止一个。

      numberOfItems = ??
      
      ' ...
      
      If numberOfItems+1 >= arr.Length Then
          Array.Resize(arr, arr.Length + 10)
      End If
      
      arr(numberOfItems) = newItem
      numberOfItems += 1
      

      同样对于A,只需要在需要时获取数组即可。

      Dim list As List(Of Integer)(arr) ' Do this only once, keep a reference to the list
                                        ' If you create a new List everything you add an item then this will never be fast
      
      '...
      
      list.Add(newItem)
      arrayWasModified = True
      
      ' ...
      
      Function GetArray()
      
          If arrayWasModified Then
              arr = list.ToArray()
          End If
      
          Return Arr
      End Function
      

      如果你有时间,我建议你将它全部转换为List并删除数组。

      * 我的代码可能无法编译

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-25
        • 1970-01-01
        • 2019-03-13
        • 2021-10-27
        • 2015-05-07
        • 1970-01-01
        • 1970-01-01
        • 2016-08-16
        相关资源
        最近更新 更多