Powershell将一个长数组拆分成一个长度为N的数组?

qf9go6mv  于 2023-06-29  发布在  Shell
关注(0)|答案(9)|浏览(99)

例如,给定一个列表1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8和一个数字4,它返回一个长度为4的列表的列表,即(1, 2, 3, 4), (5, 6, 7, 8), (1, 2, 3, 4), (5, 6, 7, 8)
基本上,我想在PowerShell中实现以下Python代码。

s = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8
z = zip(*[iter(s)]*4)  # Here N is 4
# z is (1, 2, 3, 4), (5, 6, 7, 8), (1, 2, 3, 4), (5, 6, 7, 8)

下面的脚本返回17而不是5。

$a = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,0
$b = 0..($a.Length / 4) | % {  @($a[($_*4)..($_*4 + 4 - 1)]) } 
$b.Length
2uluyalo

2uluyalo1#

这是一个有点旧,但我想我会扔在方法,我用来分割数组成块。可以将Group-Object与构造的属性一起使用:

$bigList = 1..1000

$counter = [pscustomobject] @{ Value = 0 }
$groupSize = 100

$groups = $bigList | Group-Object -Property { [math]::Floor($counter.Value++ / $groupSize) }

$groups将是GroupInfo对象的集合;在本例中,每个组将正好有100个元素(可访问为$groups[0].Group$groups[1].Group等)。我为计数器使用了一个对象属性,以避免-Property脚本块中的作用域问题,因为简单的$i++不会写回原始变量。或者,您可以使用$script:counter = 0$script:counter++,在没有自定义对象的情况下获得相同的效果。

kpbpu008

kpbpu0082#

2009年PowerShell Split-Every Function
也许可以改进。

Function Split-Every($list, $count=4) {
    $aggregateList = @()

    $blocks = [Math]::Floor($list.Count / $count)
    $leftOver = $list.Count % $count
    for($i=0; $i -lt $blocks; $i++) {
        $end = $count * ($i + 1) - 1

        $aggregateList += @(,$list[$start..$end])
        $start = $end + 1
    }    
    if($leftOver -gt 0) {
        $aggregateList += @(,$list[$start..($end+$leftOver)])
    }

    $aggregateList    
}

$s = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8

$r = Split-Every $s 4

$r[0]
""
$r[1]
""
$r[2]
""
$r[3]
p4rjhz4m

p4rjhz4m3#

PS> $a = 1..16
PS> $z=for($i=0; $i -lt $a.length; $i+=4){ ,($a[$i]..$a[$i+3])}
PS> $z.count
4    

PS> $z[0]
1
2
3
4

PS> $z[1]
5
6
7
8

PS> $z[2]
9
10
11
12

PS> $z[3]
13
14
15
16
uinbv5nw

uinbv5nw4#

使用select提供解决方案。它不需要担心$list.Count是否能被$chunkSize整除。

function DivideList {
    param(
        [object[]]$list,
        [int]$chunkSize
    )

    for ($i = 0; $i -lt $list.Count; $i += $chunkSize) {
        , ($list | select -Skip $i -First $chunkSize)
    }
}

DivideList -list @(1..17) -chunkSize 4 | foreach { $_ -join ',' }

输出:

1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
17
ui7jx7zq

ui7jx7zq5#

@Shay Levy回答:如果你把a的值改为1..15,那么你的解决方案就不再起作用了(Peter Reavy评论)
这对我很有效:

$a = 1..15
$z=for($i=0; $i -lt $a.length; $i+=4){if ($a.length -gt ($i+3)) { ,($a[$i]..$a[$i+3])} else { ,($a[$i]..$a[-1])}}
$z.count
x4shl7ld

x4shl7ld6#

$a = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,0
$b = 0..([Math]::ceiling($a.Length / 4) - 1) | 
    % {  @(, $a[($_*4)..($_*4 + 4 - 1)]) }

我不知道为什么要在(后面加逗号。

umuewwlo

umuewwlo7#

Clear-Host

$s = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18

$count = $s.Length

$split = $count/2

$split --

$b = $s[0..$split]

$split ++

$a = $s[$split..$count]

write-host "first array"

$b

write-host "next array"

$a

#clean up
Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0
zu0ti5jz

zu0ti5jz8#

一个简单的方法,使用List<T>来收集输入对象元素并输出,而不使用$PSCmdlet.WriteObject进行枚举。这与Windows PowerShell 5.1兼容。

function Split-Collection {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [object[]] $InputObject,

        [Parameter(Position = 0)]
        [ValidateRange(1, [int]::MaxValue)]
        [int] $ChunkSize = 5
    )

    begin {
        $list = [System.Collections.Generic.List[object]]::new()
    }
    process {
        foreach($item in $InputObject) {
            $list.Add($item)
            if($list.Count -eq $ChunkSize) {
                $PSCmdlet.WriteObject($list.ToArray())
                $list.Clear()
            }
        }
    }
    end {
        if($list.Count) {
            $PSCmdlet.WriteObject($list.ToArray())
        }
    }
}

用途:

PS ..\pwsh> 0..10 | Split-Collection 3 | ForEach-Object { "[$_]" }

[0 1 2]
[3 4 5]
[6 7 8]
[9 10]

PS ..\pwsh> Split-Collection -InputObject (0..10) 3 | ForEach-Object { "[$_]" }

[0 1 2]
[3 4 5]
[6 7 8]
[9 10]

如果使用PowerShell 7+,一种更简单的方法是使用LINQ的Enumerable.Chunk

PS ..\pwsh> [System.Linq.Enumerable]::Chunk([int[]] (0..10), 3) | ForEach-Object { "[$_]" }

[0 1 2]
[3 4 5]
[6 7 8]
[9 10]
jei2mxaa

jei2mxaa9#

如果集合足够大(例如数以百万计的元素),则性能可能很重要。首先,从性能的Angular 来看,以前提出的解决方案都没有让我满意。以下是我的解决方案:

Function Chunk {
    param(
        [object[]] $source,
        [int] $size = 1)
    $chunkCount = [Math]::Ceiling($source.Count / $size)
    0 .. ($chunkCount - 1) `
    | ForEach-Object {
        $startIndex = $_ * $size
        $endIndex = [Math]::Min(($_ + 1) * $size, $source.Count)
        ,$source[$startIndex .. ($endIndex - 1)]
    }
}

用法示例:

Chunk @(1..17) 4 | foreach { $_ -join ',' }

输出:

1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
17

业绩计量:

(Measure-Command { Chunk @(1..1000000) 1000 }).TotalMilliseconds

输出:140.467(毫秒)

相关问题