搜索大型Powershell阵列



警告:Powershell新手,术语/代码可能是不正确的

假设我有一个Powershell数组,其中包含来自Invoke-Sqlcmd的数据,例如10000";行";每个具有六个(Col1-Col6(列。说我想找到每一排都有一个空的Col5。现在我在做

foreach ($row in $sqlimport.col1)
{ $col5data = $sqlimport.Where({$_.col1 -eq $row}) | Select-Object -ExpandProperty Col5
if ( '' -eq $col5data ) {$col5data+1} else {} $col5data

返回1,它应该在我的测试中返回。代码似乎错误且速度缓慢。跑完全程需要几分钟。当类似的东西

$sqlimport.Where({$_.col5 -eq 'somedatathatisthere'})

耗时毫秒

然而,

$sqlimport.Where({$_.col5 -eq ''})

返回空白

($sqlimport.Where({$_.col5 -eq ''})).Count

返回0

现在,您要求PowerShell创建一个由列col1中的所有值组成的数组,然后在每次迭代中再次搜索整个数组以查找相应的col5值。这完全没有必要。

只需在阵列本身上循环:

foreach($row in $sqlimport){
if($row.Col5 -like ''){
Write-Host "Col5 is empty in row with id $($row.Col1)"
}
}

这只会在整个数组上迭代一次

Mathias的回答很好地解释了第一次尝试效率低下的问题,并提供了一个最终性能最佳的解决方案,因为使用了(单个(foreach语句(而不是慢得多的ForEach-Objectcmdlet(。

但是,使用(单个(.Where()数组方法调用(或相关的.ForEach()方法(的解决方案:

  • 稍慢[1]
  • 同时更简洁并且可以说在概念上更优雅

这就是你在$sqlimport.Where({ $_.col5 -eq '' })上尝试的,根据你的反馈,它只需要一个小的调整就可以工作:

  • 使用-like ''而不是-eq '',这是测试空字符串(''(测试$null(也在Mathias的答案中使用(的一个有点模糊的[2]快捷方式,本质上,它相当于的.NET[string]::IsNullOrEmpty()方法
# -like matches both '' and $null
$sqlimport.Where({ $_.col5 -like '' })

注:

  • 如果您希望仅测试$null,请使用以下命令;注意$null是如何放置在LHS上的,这对于鲁棒比较通常是可取的[3]:

    $sqlimport.Where({ $null -eq $_.col5 })
    
    • 顺便说一句:GitHub问题#10656建议为$null引入一个类似-is $null的简化测试;不幸的是,相关的PR已被放弃
  • 顺便说一句:[string]-类型受限的PowerShell变量从不存储$null值:
    [string] $str = $null导致$str包含'',而不是$null。但是,未在PowerShell代码中填充的[string]类型的属性值可以包含$null值,就像您的情况一样。

    • 若要在PowerShell代码中将真正的$null值传递给string类型的.NET API,必须使用特殊单例(直接传递$null将再次导致''):[NullString]::value`
    • 有关背景信息,请参阅此答案

[1]有关PowerShell各种枚举(迭代(功能的性能比较,请参阅此答案的底部

[2]-like运算符的真正目的是执行通配符表达式匹配。快捷方式依赖于
-like-仅对(非null(字符串进行操作-自动将非字符串操作数转换为字符串,在$null的情况下,这会导致转换为''(空字符串TR

[3]为了可靠地测试$null,将其放置在-eq/-ne操作的LHS上;例如$null -eq $var。如果将$null放置在RHS-$var -eq $null-上,而$var恰好是集合(例如数组(,则返回值为匹配元素的数组,即$var中那些元素的数组,其值为$null,这是一个不同的操作-请参阅about_Comparison_Operators

最新更新