【问题标题】:Creating an array with large initial size in powershell在powershell中创建一个初始大小较大的数组
【发布时间】:2021-11-03 01:50:53
【问题描述】:

我知道在 powershell 中创建数组的唯一方法是

$arr = @(1, 2, 3)

但是,如果我想创建一个初始大小较大的数组,例如 10000,这种创建方法并不方便。

因为我不想写这样的代码

$arr = @(0, 0, 0, 0, 0, 0, ... ,0) # 10000 0s in this line of code

像下面这样写代码效率不高。

$arr = @()
for ($i = 1; $i -le 10000; $i++) {
  $arr += 0
}

因为每当执行+= 运算符时,旧数组中的所有元素都会被复制到新创建的数组中。

在 powershell 中创建具有较大初始大小的数组的最佳方法是什么?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    在这种情况下使用New-Object

    PS> $arr = New-Object int[] 10000; $arr.length
    10000
    

    或者,在 PSv5+ 中,对类型使用静态 new() 方法:

    PS> $arr = [int[]]::new(10000); $arr.length
    10000
    

    这些命令创建一个强类型数组,在本例中使用基本类型[int]。 如果用例允许,出于性能和类型安全的原因,这是更可取的。

    如果您需要像 PowerShell ([System.Object[]]) 一样创建“无类型”数组,请将 object 替换为 int;例如,[object[]]::new(10000);这样一个数组的元素将默认为$null
    TessellatingHeckler's helpful answer,但是,它显示了一个更简洁的替代方案,甚至允许您将所有元素初始化为特定值。


    数组有固定的大小;如果您需要一个可以预分配动态增长的类数组数据结构,请参阅Bluecakes' helpful [System.Collections.ArrayList]-based answer

    [System.Collections.ArrayList][System.Object[]] 的可调整大小的类似物,它的 generic 等效 - 就像上面的 [int[]] 示例一样 - 允许您使用特定类型用于性能和稳健性(如果可行),是 [System.Collections.Generic.List[<type>]],例如:

    PS> $lst = [System.Collections.Generic.List[int]]::New(10000); $lst.Capacity
    10000
    

    请注意 - 与 [System.Collections.ArrayList] 一样 - 指定 初始容量10000,此处)不会分配具有该大小的内部使用的数组立即 -容量值被简单地存储(并公开为属性.Capacity),当添加第一个元素时,按需分配具有该容量的内部数组(内部大小留有增长空间)到列表中。

    [System.Collections.Generic.List[<type>]].Add() 方法值得称道 产生输出,而 [System.Collections.ArrayList] 产生输出(它返回刚刚添加的元素的索引)。

    # The non-generic ArrayList's .Add() produces (usually undesired) output.
    PS> $al = [System.Collections.ArrayList]::new(); $al.Add('first elem')
    0  # .Add() outputs the index of the newly added item
    
    # Simplest way to suppress this output:
    PS> $null = $al.Add('first elem')
    # NO output.
    
    # The generic List[T]'s .Add() does NOT produce output.
    PS> $gl = [System.Collections.Generic.List[string]]::new(); $gl.Add('first elem')
    # NO output from .Add()
    

    【讨论】:

      【解决方案2】:

      数组字面量乘法:

      $arr = @($null) * 10000
      

      【讨论】:

      • 做得很好。对于创建常规 PowerShell 数组 ([System.Object[]]),这是迄今为止最简单的解决方案,它也允许使用特定值进行初始化。 (对于非常大的数组,这种初始化是有代价的,但这可能并不重要)。为了使其特定于 OP 的示例:$arr = , 0 * 10000.
      • 这完全是个狡辩,但也许很有趣:@($null) 是数组子表达式运算符的应用,而不是 数组字面量。甚至, $null 也不是数组字面量——它是数组构造运算符, 的应用。引用PowerShell in Action, 2nd Edition 的话:“这是在 PowerShell 中定义数组字面量的方式:它们不是。PowerShell 中没有数组字面量表示法。 [...] 不是数组字面量,而是一组根据需要创建集合的操作。"
      • @mklement0 这很有趣,我看到逗号被解析为“运算符”,但我想知道与“文字”相比,它有什么有意义的区别?它是否与它在运行时更接近动态/评估有关,例如与能够做到$a, $b有关吗? "foo" 大概是一个字符串文字,但这是否意味着 "$foo" 不是?
      • 我猜这意味着在 PS 中初始化数组没有单独的专用语法(例如C#的{ …, …, … })——只是帮助您按需构建数组的运算符。这与数组 elements 是否为字面量无关。
      【解决方案3】:

      PowerShell 中你是正确的,+= 将销毁旧数组并使用新项目创建一个新数组。

      为了处理大量项目,我强烈建议使用 .NET 中的 ArrayList 类型,因为这不是固定大小的数组,因此 PowerShell 不会在您每次向其中添加项目时破坏它,我发现这在我的项目中效果更好。

      使用ArrayList 也意味着您不需要从 10000 个项目开始。因为PowerShell 不需要每次都重新创建数组,所以您可以从 0 开始,然后根据需要添加每个项目,而不是从 10000 开始。

      所以在你的脚本中我会像这样创建一个空的ArrayList

      [System.Collections.ArrayList]$arr = @()
      

      然后当您需要向其中添加内容时,只需调用 .Add()(您无需使用 10000 个项目预填充数组,它会随着您添加项目而扩展)。

      $arr.Add([int]0)
      

      您使用ArrayList 的示例:

      [System.Collections.ArrayList]$arr = @()
      for ($i = 1; $i -le 10000; $i++) {
          $arr.Add([int]0)
      }
      

      【讨论】:

      • 做得很好。我可以建议您还展示如何指定初始容量吗?另外,值得指出的是,.Add() 方法会产生输出(添加元素的索引),这可能是出乎意料的,$null = $arr.Add([int] 0) 是抑制该输出的一种方法。
      【解决方案4】:

      你总是可以这样做的:

      $a = @(0..9999)
      $a.length
      

      这几乎就像您已经在做的一样,只是您不必这样做 写出所有的值。

      【讨论】:

      • 范围运算符表达式周围的@(...) 实质上创建了数组两次,这是不可取的;只需使用$a = 0...9999。也就是说,OP 似乎想要将所有数组元素初始化为 0
      猜你喜欢
      • 2012-08-03
      • 1970-01-01
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-21
      • 1970-01-01
      • 2017-12-20
      相关资源
      最近更新 更多