首页 > 解决方案 > 在 powershell 中切片数组(或列表)的更好方法

问题描述

如何在 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
    }

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

谢谢你。

标签: powershelldata-partitioning

解决方案


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

$users[0..29]

您也不必担心超出数组的末尾。如果有 100 个项目并且您正在调用$array[90..119],您将获得数组中的最后 10 个项目并且没有错误。您也可以在那里使用变量和表达式:

$users[$i..($i + 29)]

这是$ith 值和 th 值之后的下 29$i个值(如果它们存在)。

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

$array = @()
loop-construct {
   $array += $value
}

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

相反,只需这样做:

$array = loop-construct {
   $value
}

字符串同样是不可变的,并且与+=操作符有同样的问题。如果您需要通过连接构建字符串,则应使用 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++
}

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

我相信你也可以用Select-Objectand来写这个Group-Object,但与上面的相比,这将是相当复杂的,并且Group-Object在 PowerShell 6 之前它的性能并不完全为人所知。


推荐阅读