在 powershell 中对数组(或列表)进行切片的更好方法

Yan*_* F. 1 powershell data-partitioning

我如何将邮件地址导出为 CSV 文件,每个用户的范围为 30 个用户。我已经尝试过这个

    $users = Get-ADUser -Filter * -Properties Mail 
    $nbCsv = [int][Math]::Ceiling($users.Count/30)
    For($i=0; $i -le $nbCsv; $i++){
        $arr=@()
        For($j=(0*$i);$j -le ($i + 30);$j++){
            $arr+=$users[$j]
        }
        $arr|Export-Csv -Path ($PSScriptRoot + "\ASSFAM" + ("{0:d2}" -f ([int]$i)) + ".csv") -Delimiter ";" -Encoding UTF8 -NoTypeInformation
    }
Run Code Online (Sandbox Code Playgroud)

它有效,但是我认为有更好的方法来完成这项任务。你有什么想法吗?

谢谢。

Bac*_*its 5

如果您想要数组的子集,则可以使用..范围运算符。数组的前 30 个元素为:

$users[0..29]
Run Code Online (Sandbox Code Playgroud)

通常,您也不必担心超出数组末尾(请参阅下面 mkelement0 的注释)。如果有 100 个项目并且您正在调用$array[90..119],您将获得数组中的最后 10 个项目并且不会出现错误。您也可以在那里使用变量和表达式:

$users[$i..($i + 29)]
Run Code Online (Sandbox Code Playgroud)

这是第$ith 个值以及第 th 个值之后的接下来 29 个值$i(如果存在)。

此外,在 PowerShell 中应避免这种模式:

$array = @()
loop-construct {
   $array += $value
}
Run Code Online (Sandbox Code Playgroud)

数组在 .Net 中是不可变的,因此在 PowerShell 中也是不可变的。这意味着向数组添加一个元素+=意味着“创建一个全新的数组,复制每个元素,然后将这个新项目放在上面,然后删除旧数组。” 它会产生巨大的内存压力,如果您正在处理超过几百个项目,速度会明显变慢。

相反,只需这样做:

$array = loop-construct {
   $value
}
Run Code Online (Sandbox Code Playgroud)

字符串同样是不可变的,并且对于运算符也有同样的问题+=。如果需要通过连接构建字符串,则应使用 StringBuilder 类。

然而,最终我会这样写:

$users = Get-ADUser -Filter * -Properties Mail 
$exportFileTemplate = Join-Path -Path $PSScriptRoot -ChildPath 'ASSFAM{0:d2}.csv'

$batchSize = 30

$batchNum = 0
$row = 0
while ($row -lt $users.Count) {
    $users[$row..($row + $batchSize - 1)] | Export-Csv ($exportFileTemplate -f $batchNum) -Encoding UTF8 -NoTypeInformation
    $row += $batchSize
    $batchNum++
}
Run Code Online (Sandbox Code Playgroud)

$row从技术上讲,可以$batchNum将其合并到一个变量中,但这更具可读性,IMO。

我确信您也可以使用 和 来编写此代码Select-ObjectGroup-Object但是与上面的代码相比,这将相当复杂,并且Group-Object在 PowerShell 6 之前并不完全了解它的性能。


如果您使用Powershell 的严格模式(在某些配置或场景中可能需要这种模式),那么您需要检查是否枚举超出了数组末尾。你可以这样做:

while ($row -lt $users.Count) {
    $users[$row..([System.Math]::Min(($row + $batchSize - 1),($users.Count - 1)))] | Export-Csv ($exportFileTemplate -f $batchNum) -Encoding UTF8 -NoTypeInformation
    $row += $batchSize
    $batchNum++
}
Run Code Online (Sandbox Code Playgroud)

我相信这是正确的,但我在这个逻辑中可能有一个微小的错误。我还没有完全测试过。