powershell 比较运算符包含 vs 大数组
powershell comparison operator contain vs large array
想知道是否有机会提高以下数组搜索的性能。现在是16秒
Measure-Command -Expression {
$a = @()
$b = @()
1..10000 | %{$a += $_}
1..10000 | %{$b += $_}
#Try to resize but still running 16 seconds
[array]::Resize([ref]$a,10000)
[array]::Resize([ref]$b,10000)
foreach ($i in $a){
if ($b -contains $i) {
#write-host $i
}
}
}
+=
在数组的情况下 重新创建整个数组:它将旧内容与新元素一起复制到新数组中。这可以说是在 PowerShell 中填充大型数组的最糟糕的方法。仅当它是不在循环内的一次性操作,或者数组很小且时间无关紧要时才使用 +=
。
直接填充数组:
$a = 1..10000
或者直接收集foreach
语句的输出:
$a = foreach ($i in 1..10000) { $i }
或者使用 ArrayList:
$a = [Collections.ArrayList]@()
foreach ($i in 1..10000) { $a.Add($i) >$null }
请注意,在这种特殊情况下,将现有数组转换为 ArrayList 会更快:
$a = [Collections.ArrayList]@(1..10000)
流水线是一项复杂的操作,它比 foreach
(语句,不是 cmdlet)、while
、[=22 等流控制语句慢 several/many 倍=].
ScriptBlock(ForEach
cmdlet中大括号{ }
中的代码,别名%
)取一个与内部的简单代码相比,为每个元素创建执行上下文需要很多时间。
-contains
检查每个元素,直到找到匹配项,因此最终迭代次数在最坏情况下为 $a.count * $b.count
或平均为一半。
最有效的方法是构建查找 table:
作为散列table:
$a = 1..10000
$b = 1..10000
$bIndex = @{}
foreach ($i in $b) { $bIndex[$i] = $true }
foreach ($i in $a) {
if ($bIndex[$i]) {
#write-host $i
}
}
15 milliseconds on i7 CPU
作为 HashSet(.NET 3.5 及更新版本,built-in since Win7,可安装在 XP 上):
$a = 1..10000
$b = 1..10000
$bIndex = [Collections.Generic.HashSet[int]]$b
foreach ($i in $a) {
if ($bIndex.Contains($i)) {
#write-host $i
}
}
7 milliseconds on i7 CPU
使用 HashSet 将数组相交,然后迭代结果:
$a = 1..10000
$b = 1..10000
$inBoth = [Collections.Generic.HashSet[int]]$a
$inBoth.IntersectWith([Collections.Generic.HashSet[int]]$b)
foreach ($i in $inBoth) {
#write-host $i
}
7 milliseconds on i7 CPU
如果数组的内容不同,即当交集比数组小得多时,速度会快很多倍。
也可以在数组中构建一个真正的 - 在重复值的情况下很有用。
想知道是否有机会提高以下数组搜索的性能。现在是16秒
Measure-Command -Expression {
$a = @()
$b = @()
1..10000 | %{$a += $_}
1..10000 | %{$b += $_}
#Try to resize but still running 16 seconds
[array]::Resize([ref]$a,10000)
[array]::Resize([ref]$b,10000)
foreach ($i in $a){
if ($b -contains $i) {
#write-host $i
}
}
}
+=
在数组的情况下 重新创建整个数组:它将旧内容与新元素一起复制到新数组中。这可以说是在 PowerShell 中填充大型数组的最糟糕的方法。仅当它是不在循环内的一次性操作,或者数组很小且时间无关紧要时才使用+=
。直接填充数组:
$a = 1..10000
或者直接收集
foreach
语句的输出:$a = foreach ($i in 1..10000) { $i }
或者使用 ArrayList:
$a = [Collections.ArrayList]@() foreach ($i in 1..10000) { $a.Add($i) >$null }
请注意,在这种特殊情况下,将现有数组转换为 ArrayList 会更快:
$a = [Collections.ArrayList]@(1..10000)
流水线是一项复杂的操作,它比
foreach
(语句,不是 cmdlet)、while
、[=22 等流控制语句慢 several/many 倍=].ScriptBlock(
ForEach
cmdlet中大括号{ }
中的代码,别名%
)取一个与内部的简单代码相比,为每个元素创建执行上下文需要很多时间。-contains
检查每个元素,直到找到匹配项,因此最终迭代次数在最坏情况下为$a.count * $b.count
或平均为一半。
最有效的方法是构建查找 table:
作为散列table:
$a = 1..10000 $b = 1..10000 $bIndex = @{} foreach ($i in $b) { $bIndex[$i] = $true } foreach ($i in $a) { if ($bIndex[$i]) { #write-host $i } }
15 milliseconds on i7 CPU
作为 HashSet(.NET 3.5 及更新版本,built-in since Win7,可安装在 XP 上):
$a = 1..10000 $b = 1..10000 $bIndex = [Collections.Generic.HashSet[int]]$b foreach ($i in $a) { if ($bIndex.Contains($i)) { #write-host $i } }
7 milliseconds on i7 CPU
使用 HashSet 将数组相交,然后迭代结果:
$a = 1..10000 $b = 1..10000 $inBoth = [Collections.Generic.HashSet[int]]$a $inBoth.IntersectWith([Collections.Generic.HashSet[int]]$b) foreach ($i in $inBoth) { #write-host $i }
7 milliseconds on i7 CPU
如果数组的内容不同,即当交集比数组小得多时,速度会快很多倍。
也可以在数组中构建一个真正的