在 PowerShell 中处理大型数组

Processing large arrays in PowerShell

我很难理解在 PowerShell 中处理大型 datasets/arrays 的最有效方法。我的数组包含数百万个需要处理和分组的项目。这个列表的大小总是不同的,这意味着它可能是 350 万个项目或 1000 万个项目。

示例:350 万个项目按“4”分组,如下所示:

项目 0,1,2,3 组合在一起 4,5,6,7 组合在一起等等。

我已经尝试使用单个线程处理数组,方法是循环遍历列表并分配给 pscustomobject,它只需要 45-50 多分钟即可完成。

我也曾尝试将数组分解成更小的数组,但这导致过程 运行 甚至更长。

$i=0
$d_array = @()
$item_array # Large dataset


While ($i -lt $item_array.length){

    $o = "Test"
    $oo = "Test"
    $n = $item_array[$i];$i++
    $id = $item_array[$i];$i++
    $ir = $item_array[$i];$i++
    $cs = $item_array[$i];$i++

    $items = [PSCustomObject]@{
        'field1' = $o
        'field2' = $oo
        'field3' = $n
        'field4' = $id
        'field5' = $ir
        'field6'= $cs
    }
    $d_array += $items

}

我可以想象,如果我应用一个作业调度程序,允许我 运行 多个作业将大大减少处理时间,但我想让其他人采取快速有效的方式来解决这个问题。

这个怎么样?快 32.5 倍。用 += 制作数组会杀死小狗。它每次都复制整个数组。

$i=0
$item_array = 1..100000 # Large dataset

'measuring...'

# original 1 min 5 sec                                                                 
# mine 2 sec              
# other answer, 2 or 3 sec
# c# version 0.029 sec, 2241x faster!

measure-command {

$d_array = 
While ($i -lt $item_array.length){
    $o = "Test"
    $oo = "Test"
    $n = $item_array[$i];$i++                                                      
    $id = $item_array[$i];$i++                                                     
    $ir = $item_array[$i];$i++                                                     
    $cs = $item_array[$i];$i++      
    # $items =                                               
    [PSCustomObject]@{
        'field1' = $o
        'field2' = $oo
        'field3' = $n
        'field4' = $id
        'field5' = $ir
        'field6'= $cs
    }
    # $d_array += $items
}

}

您可以使用 ArrayList, or perhaps even better by using a strongly typed List 对此进行一些优化,但遍历数组中的数百万个元素仍然需要时间..

至于您的代码:无需先捕获变量中的数组项值,然后再使用它添加到 PSCustomObject。

$item_array = 'a','b','c','d','e','f','g','h' # Large dataset
$result = New-Object System.Collections.Generic.List[PSCustomObject]
# or use an ArrayList: $result = New-Object System.Collections.ArrayList

$i = 0
While ($i -lt $item_array.Count) {
    [void]$result.Add(
        [PSCustomObject]@{
            'field1' = "Test" # $o
            'field2' = "Test" # $oo
            'field3' = $item_array[$i++]  #$n
            'field4' = $item_array[$i++]  #$id
            'field5' = $item_array[$i++]  #$ir
            'field6' = $item_array[$i++]  #$cs
        }
    )
}

# save to a CSV file maybe ?
$result | Export-Csv 'D:\blah.csv' -NoTypeInformation

如果需要结果再次变成'normal'数组,使用$result.ToArray()

如果您处理的是大数据,使用 C# 也很有效。

Add-Type -TypeDefinition @"
using System.Collections.Generic;

public static class Test
{
    public static List<object> Convert(object[] src)
    {
        var result = new List<object>();
        for(var i = 0; i <= src.Length - 4; i+=4)
        {
            result.Add( new {
                field1 = "Test",
                field2 = "Test",
                field3 = src[i + 0],
                field4 = src[i + 1],
                field5 = src[i + 2],
                field6 = src[i + 3]
            });
        }
        return result;
    }
}
"@

$item_array = 1..10000000
$result = [Test]::Convert($item_array)

虽然s version is unsurpassed, here my try with my local measurements from

同样$item_array = 1..100000适用于所有版本

> .\SO_56406847.ps1
measuring...BDups
measuring...LotPings
measuring...Theo
measuring...js2010
measuring...rokumaru
BDups    = 75,9949897 TotalSeconds
LotPings = 2,3663763 TotalSeconds
Theo     = 2,4469917 TotalSeconds
js2010   = 2,9198114 TotalSeconds
rokumaru = 0,0109287 TotalSeconds

## Q:\Test19\SO_56406847.ps1
$i=0
$item_array = 1..100000  # Large dataset

'measuring...LotPings'
$LotPings = measure-command {
    $d_array = for($i=0;$i -lt $item_array.length;$i+=4){
        [PSCustomObject]@{
            'field1' = "Test"
            'field2' = "Test"
            'field3' = $item_array[$i]
            'field4' = $item_array[$i+1]
            'field5' = $item_array[$i+2]
            'field6' = $item_array[$i+3]
        }
    }
} # measure-command