Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 将PowerShell阵列切片为一组较小的阵列_Arrays_Powershell_Data Partitioning - Fatal编程技术网

Arrays 将PowerShell阵列切片为一组较小的阵列

Arrays 将PowerShell阵列切片为一组较小的阵列,arrays,powershell,data-partitioning,Arrays,Powershell,Data Partitioning,我想基于一个变量将单个数组转换为一组较小的数组。因此,当大小为3时,0,1,2,3,4,5,6,7,8,9将变成0,1,2,3,4,5,6,7,8,9 我目前的做法是: $ids=@(0,1,2,3,4,5,6,7,8,9) $size=3 0..[math]::Round($ids.count/$size) | % { # slice first elements $x = $ids[0..($size-1)] # redefine array w/ remai

我想基于一个变量将单个数组转换为一组较小的数组。因此,当大小为3时,0,1,2,3,4,5,6,7,8,9将变成0,1,2,3,4,5,6,7,8,9

我目前的做法是:

$ids=@(0,1,2,3,4,5,6,7,8,9)
$size=3

0..[math]::Round($ids.count/$size) | % { 

    # slice first elements
    $x = $ids[0..($size-1)]

    # redefine array w/ remaining values
    $ids = $ids[$size..$ids.Length]

    # return elements (as an array, which isn't happening)
    $x

} | % { "IDS: $($_ -Join ",")" }
产生:

IDS: 0
IDS: 1
IDS: 2
IDS: 3
IDS: 4
IDS: 5
IDS: 6
IDS: 7
IDS: 8
IDS: 9
我希望是:

IDS: 0,1,2
IDS: 3,4,5
IDS: 6,7,8
IDS: 9
我遗漏了什么?

您可以使用$x,而不仅仅是$x

文档中的“关于操作员”部分包含以下内容:

, Comma operator                                                  
   As a binary operator, the comma creates an array. As a unary
   operator, the comma creates an array with one member. Place the
   comma before the member.

为了完整起见:

function Slice-Array
{

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$True)]
        [String[]]$Item,
        [int]$Size=10
    )
    BEGIN { $Items=@()}
    PROCESS {
        foreach ($i in $Item ) { $Items += $i }
    }
    END {
        0..[math]::Floor($Items.count/$Size) | ForEach-Object { 
            $x, $Items = $Items[0..($Size-1)], $Items[$Size..$Items.Length]; ,$x
        } 
    }
}
用法:

@(0,1,2,3,4,5,6,7,8,9) | Slice-Array -Size 3 | ForEach-Object { "IDs: $($_ -Join ",")" }
要添加解释,请执行以下操作:

隐式或使用return输出集合(如数组[1])会通过;也就是说,集合被枚举并展开:

# Count objects received.
PS> (1..3 | Measure-Object).Count
3   # Array elements were sent *individually* through the pipeline.
使用的一元形式防止枚举是一种方便简洁但有点晦涩的解决方法:

也就是说,围绕原始集合创建一个临时的单元素辅助数组,以便枚举仅应用于辅助数组,将封闭的原始集合原样作为单个对象输出

一种概念上更清晰、但更详细、更慢的方法是使用,这清楚地表明了将集合作为单个对象输出的意图

目视检查方面的缺陷:

在输出显示时,多个阵列之间的边界似乎再次被擦除:

PS> (1..2), (3..4) # Output two arrays without enumeration
1
2
3
4
也就是说,尽管两个2元素数组分别作为单个对象发送,但输出通过在各自的行上显示元素,使其看起来像一个平面的4元素数组

一种简单的方法是对每个数组进行字符串化,将每个数组转换为一个字符串,其中包含以空格分隔的元素列表

PS> (1..2), (3..4) | ForEach-Object { "$_" }
1 2
3 4
现在很明显,收到了两个单独的阵列

[1] 列举了哪些数据类型: 实现IEnumerable接口的数据类型实例会自动枚举,但也有例外: 也实现IDictionary的类型(如哈希表)不会枚举,XmlNode实例也不会枚举。 相反,未实现IEnumerable的DataTable实例被枚举为其.Rows集合的元素-请参阅
此外,请注意,外部程序的标准输出是逐行枚举的。

Craig自己已经方便地将分割分区功能包装在一个:

让我提供一个性能更好的it PSv3+语法的演变,重命名为Split Array,它:

使用可扩展的System.Collections.Generic.List[object]]集合更有效地收集输入对象

在拆分期间不修改集合,而是从中提取元素的范围

对于较小的输入集合,优化不会有多大影响,但一旦进入数千个元素,速度可能会显著加快:

要大致了解性能改进,请使用:

使用Windows 5.1的单核Windows 10虚拟机的示例结果绝对时间并不重要,但因素如下:

命令秒10运行平均时间间隔系数 ---- --------- ---- --- $ids |拆分阵列-大小$size 0.150 00:00:00.1498207 1.00 $ids |片阵列-大小$size 10.382 00:00:10.3820590 69.30 请注意,未优化的函数几乎慢了70倍。

您只需将$id分配给$x,然后将其发送到流中,由|%{进行迭代。请使用$x,而不仅仅是$x。
PS> (Write-Output -NoEnumerate (1..3) | Measure-Object).Count 
1   # Write-Output -NoEnumerate prevented enumeration.
PS> (1..2), (3..4) # Output two arrays without enumeration
1
2
3
4
PS> (1..2), (3..4) | ForEach-Object { "$_" }
1 2
3 4
function Split-Array {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [String[]] $InputObject
        ,
        [ValidateRange(1, [int]::MaxValue)]
        [int] $Size = 10
    )
    begin   { $items = New-Object System.Collections.Generic.List[object] }
    process { $items.AddRange($InputObject) }
    end {
      $chunkCount = [Math]::Floor($items.Count / $Size)
      foreach ($chunkNdx in 0..($chunkCount-1)) {
        , $items.GetRange($chunkNdx * $Size, $Size).ToArray()
      }
      if ($chunkCount * $Size -lt $items.Count) {
        , $items.GetRange($chunkCount * $Size, $items.Count - $chunkCount * $Size).ToArray()
      }
    }
}
$ids = 0..1e4 # 10,000 numbers
$size = 3 # chunk size

Time-Command { $ids | Split-Array -size $size }, # optimized
             { $ids | Slice-Array -size $size }  # original