在 PowerShell 中针对大型数组的批量正则表达式删除速度非常慢
Bulk regex removals against large array very slow in PowerShell
我正在尝试找到最快/最有效的方法来 运行 对数组进行许多正则表达式删除。
我的 $hosts
数组包含数万个单独的项目,采用域格式。例如:
test.domain.xyz
domain.xyz
something.com
anotherdomain.net
我的 $local_regex
数组包含约 1000 个多行格式的独立正则表达式。例如:
^广告。 (ad.*)
domain.xyz$ (*domain.xyz)
我目前正在尝试通过以下方式排除任何正则表达式匹配项,但是对于大型数组和许多要匹配的正则表达式来说速度非常慢:
Function Regex-Remove
{
Param
(
[Parameter(Mandatory=$true)]
$local_regex,
[Parameter(Mandatory=$true)]
$hosts
)
# Loop through each regex and select only non-matching items
foreach($regex in $local_regex)
{
# Multi line, case insensitive
$regex = "(?im)$regex"
# Select hosts that do not match regex
$hosts = $hosts -notmatch $regex
}
return $hosts
}
有更好的方法吗?
重新分配大型数组的成本很高。更改数组的大小需要分配一个新数组并将内容复制到其中。例如,如果您有 10,000 个主机名和 1,000 个正则表达式,则您有 10,000,000 次复制操作。这将产生一些可衡量的效果。有一个 cmdlet Measure-Command
用于计算执行时间。
作为替代方法,尝试使用索引数组并用 $null
值覆盖不需要的值。像这样,
foreach($regex in $local_regex) {
$regex = "(?im)$regex"
for($i=0;$i -lt $hosts.length; ++$i) {
if( $hosts[$i] -match $regex) {
$hosts[$i] = $null
}
}
}
您可以使用 System.Collections.ArrayList 对象而不是数组,这将使过程更快,并且您可以使用方法添加/删除项目而无需重建整个数组
$var = New-Object System.Collections.ArrayList
$var.Add()
$var.AddRange()
$var.Remove()
$var.RemoveRange()
根据@Roberto 的建议,我将 $hosts
数组切换为 New-Object System.Collections.ArrayList
即时从 ArrayList 中删除的能力正是我所需要的,而 while 循环确保删除重复值。
Function Regex-Remove
{
Param
(
[Parameter(Mandatory=$true)]
$local_regex,
[Parameter(Mandatory=$true)]
$hosts
)
# Loop through each regex and select only non-matching items
foreach($regex in $local_regex)
{
# Multi line, case insensitive
$regex = "(?i)$regex"
# Select hosts that do not match regex
$hosts -match $regex | % {
while($hosts.Contains($_))
{
$hosts.Remove($_)
}
}
}
return $hosts
}
我正在尝试找到最快/最有效的方法来 运行 对数组进行许多正则表达式删除。
我的 $hosts
数组包含数万个单独的项目,采用域格式。例如:
test.domain.xyz
domain.xyz
something.com
anotherdomain.net
我的 $local_regex
数组包含约 1000 个多行格式的独立正则表达式。例如:
^广告。 (ad.*)
domain.xyz$ (*domain.xyz)
我目前正在尝试通过以下方式排除任何正则表达式匹配项,但是对于大型数组和许多要匹配的正则表达式来说速度非常慢:
Function Regex-Remove
{
Param
(
[Parameter(Mandatory=$true)]
$local_regex,
[Parameter(Mandatory=$true)]
$hosts
)
# Loop through each regex and select only non-matching items
foreach($regex in $local_regex)
{
# Multi line, case insensitive
$regex = "(?im)$regex"
# Select hosts that do not match regex
$hosts = $hosts -notmatch $regex
}
return $hosts
}
有更好的方法吗?
重新分配大型数组的成本很高。更改数组的大小需要分配一个新数组并将内容复制到其中。例如,如果您有 10,000 个主机名和 1,000 个正则表达式,则您有 10,000,000 次复制操作。这将产生一些可衡量的效果。有一个 cmdlet Measure-Command
用于计算执行时间。
作为替代方法,尝试使用索引数组并用 $null
值覆盖不需要的值。像这样,
foreach($regex in $local_regex) {
$regex = "(?im)$regex"
for($i=0;$i -lt $hosts.length; ++$i) {
if( $hosts[$i] -match $regex) {
$hosts[$i] = $null
}
}
}
您可以使用 System.Collections.ArrayList 对象而不是数组,这将使过程更快,并且您可以使用方法添加/删除项目而无需重建整个数组
$var = New-Object System.Collections.ArrayList
$var.Add()
$var.AddRange()
$var.Remove()
$var.RemoveRange()
根据@Roberto 的建议,我将 $hosts
数组切换为 New-Object System.Collections.ArrayList
即时从 ArrayList 中删除的能力正是我所需要的,而 while 循环确保删除重复值。
Function Regex-Remove
{
Param
(
[Parameter(Mandatory=$true)]
$local_regex,
[Parameter(Mandatory=$true)]
$hosts
)
# Loop through each regex and select only non-matching items
foreach($regex in $local_regex)
{
# Multi line, case insensitive
$regex = "(?i)$regex"
# Select hosts that do not match regex
$hosts -match $regex | % {
while($hosts.Contains($_))
{
$hosts.Remove($_)
}
}
}
return $hosts
}