Arrays 选择PowerShell中数组的所有对象的一个属性值

Arrays 选择PowerShell中数组的所有对象的一个属性值,arrays,powershell,member-enumeration,Arrays,Powershell,Member Enumeration,假设我们有一个对象数组$objects。假设这些对象具有“Name”属性 这就是我想做的 $results = @() $objects | %{ $results += $_.Name } 这是可行的,但能用更好的方式吗 如果我这样做: $results = objects | select Name $results是具有Name属性的对象数组。我希望$results包含一个名称数组 有更好的方法吗?我想您可以使用选择对象的ExpandProperty参数 例如,要获取当前目录的列

假设我们有一个对象数组$objects。假设这些对象具有“Name”属性

这就是我想做的

 $results = @()
 $objects | %{ $results += $_.Name }
这是可行的,但能用更好的方式吗

如果我这样做:

 $results = objects | select Name
$results
是具有Name属性的对象数组。我希望$results包含一个名称数组


有更好的方法吗?

我想您可以使用
选择对象的
ExpandProperty
参数

例如,要获取当前目录的列表并仅显示Name属性,可以执行以下操作:

ls | select -Property Name
ls | select -ExpandProperty Name
这仍然返回DirectoryInfo或FileInfo对象。您始终可以通过管道(别名
gm
)检查通过管道的类型

因此,要将对象扩展为您正在查看的属性类型,可以执行以下操作:

ls | select -Property Name
ls | select -ExpandProperty Name
在您的情况下,只需执行以下操作即可将变量设置为字符串数组,其中字符串是Name属性:

$objects = ls | select -ExpandProperty Name

作为更简单的解决方案,您可以使用:

$results = $objects.Name

它应该用
$objects

中元素的所有“Name”属性值数组填充
$results
,以补充先前存在的有用答案,并提供何时使用哪种方法以及性能比较的指导

  • 在管道[1]之外,使用(PSv3+):

  • 如果首先从内存中的(管道)命令收集所有输出是可行的,还可以将管道与成员枚举相结合;e、 g:

     (Get-ChildItem -File | Where-Object Length -lt 1gb).Name
    
  • 权衡

    • 输入收集和输出数组必须作为一个整体装入内存。
    • 如果输入集合本身是命令(管道)的结果(例如,
      (Get ChildItem).Name
      ),则必须先运行该命令,直到完成,然后才能访问生成的数组元素
  • 在管道中,如果必须将结果传递给另一个命令,特别是如果原始输入不能作为一个整体放入内存,请使用: $objects | Select-Object -ExpandProperty Name
    在中更全面地讨论的PSv4+是另一个性能良好的备选方案,但请注意,它要求首先收集内存中的所有输入,就像成员枚举一样:

    # By property name (string):
    $objects.ForEach('Name')
    
    # By script block (more flexibility; like ForEach-Object)
    $objects.ForEach({ $_.Name })
    
    • 此方法与成员枚举类似,具有相同的权衡,只是不应用管道逻辑;它比成员枚举稍微慢一些,尽管仍然明显快于管道

    • >P>通过名称(字符串参数)提取单个属性值,此解决方案与成员枚举(尽管后者在语法上更简单)相同。

    • 脚本块变量(
      {…}
      )允许任意转换
      ;它比基于管道的cmdlet(
      %
      更快—一次全部在内存中—可供选择

    注意:
    .ForEach()
    数组方法与its(内存中的等效对象)一样,总是返回集合(的实例),即使只生成一个输出对象。
    相比之下,成员枚举、
    Select Object
    ForEach Object
    Where Object
    按原样返回单个输出对象,而不将其包装到集合(数组)中


    比较各种方法的性能 以下是各种方法的样本计时,基于
    10000
    对象的输入集合,平均10次运行;绝对数字并不重要,并且会根据许多因素而变化,但它应该让您感觉到相对性能(计时来自单核Windows 10虚拟机:

    重要

    • 相对性能取决于输入对象是常规.NET类型的实例(例如,作为
      Get ChildItem
      的输出)还是
      [pscustomobject]
      实例(例如,作为
      Convert FromCsv
      的输出)。

      原因是
      [pscustomobject]
      属性由PowerShell动态管理,它可以比(静态定义的)常规.NET类型的常规属性更快地访问它们。下面将介绍这两种情况

    • 这些测试使用完整集合中已存在的内存作为输入,以便关注纯属性提取性能。使用流式cmdlet/函数调用作为输入,性能差异通常不会太明显,因为在该调用中花费的时间可能占所花费时间的大部分

    • 为简洁起见,别名
      %
      用于
      ForEach对象
      cmdlet

    一般结论,适用于常规.NET类型和
    [pscustomobject]
    输入:

    • 成员枚举(
      $collection.Name
      )和
      foreach($collection中的obj)
      解决方案是目前最快的
      ,比最快的基于管道的解决方案快10倍或更多

    • 令人惊讶的是,
      %Name
      的性能比
      %{$\u.Name}
      差得多-请参阅

    • PowerShell核心在这方面始终优于Windows PowerShell

    常规.NET类型的计时

    • PowerShell核心版本7.0.0-preview.3
    系数命令秒(平均运行10次)
    ------ -------                                       ------------------
    1.00$objects.Name 0.005
    1.06 foreach($o,单位为$obj)
    
    $objects | % Name      # short for: $objects | ForEach-Object -Process { $_.Name }
    
    # By property name (string):
    $objects.ForEach('Name')
    
    # By script block (more flexibility; like ForEach-Object)
    $objects.ForEach({ $_.Name })
    
    irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
    
    $count = 1e4 # max. input object count == 10,000
    $runs  = 10  # number of runs to average 
    
    # Note: Using [pscustomobject] instances rather than instances of 
    #       regular .NET types changes the performance characteristics.
    # Set this to $true to test with [pscustomobject] instances below.
    $useCustomObjectInput = $false
    
    # Create sample input objects.
    if ($useCustomObjectInput) {
      # Use [pscustomobject] instances.
      $objects = 1..$count | % { [pscustomobject] @{ Name = "$foobar_$_"; Other1 = 1; Other2 = 2; Other3 = 3; Other4 = 4 } }
    } else {
      # Use instances of a regular .NET type.
      # Note: The actual count of files and folders in your file-system
      #       may be less than $count
      $objects = Get-ChildItem / -Recurse -ErrorAction Ignore | Select-Object -First $count
    }
    
    Write-Host "Comparing property-value extraction methods with $($objects.Count) input objects, averaged over $runs runs..."
    
    # An array of script blocks with the various approaches.
    $approaches = { $objects | Select-Object -ExpandProperty Name },
                  { $objects | % Name },
                  { $objects | % { $_.Name } },
                  { $objects.ForEach('Name') },
                  { $objects.ForEach({ $_.Name }) },
                  { $objects.Name },
                  { foreach($o in $objects) { $o.Name } }
    
    # Time the approaches and sort them by execution time (fastest first):
    Time-Command $approaches -Count $runs | Select Factor, Command, Secs*
    
     $files.length # evaluates to array length
    
     $objarr.capacity