Создание Arraylist Arraylist путем разрезания существующего Arraylist - PullRequest
0 голосов
/ 03 мая 2020

У меня определена следующая переменная

$A =  New-Object -TypeName "System.Collections.ArrayList"

Теперь я добавляю к ней n элементов:

$A.Add(1..n)

Теперь я хочу разделить $A на p части из k элементов каждый (последний может иметь меньшие элементы, если p*k>$A.count). Как мне это сделать?

Ответы [ 2 ]

5 голосов
/ 03 мая 2020

Вы можете использовать функцию для разделения массива на несколько меньших массивов. Ниже приведена немного адаптированная версия этой функции здесь :

function Split-Array {
    [CmdletBinding(DefaultParametersetName = 'ByChunkSize')]
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        $Array,

        [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'ByChunkSize')]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$ChunkSize,

        [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'ByParts')]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$Parts
    )

    $items = $Array.Count
    switch ($PsCmdlet.ParameterSetName) {
        'ByChunkSize'  { $Parts = [Math]::Ceiling($items / $ChunkSize) }
        'ByParts'      { $ChunkSize = [Math]::Ceiling($items / $Parts) }
        default        { throw "Split-Array: You must use either the Parts or the ChunkSize parameter" }
    }

    # when the given ChunkSize is larger or equal to the number of items in the array
    # use TWO unary commas to return the array as single sub array of the result.
    if ($ChunkSize -ge $items) { return ,,$Array }

    $result = for ($i = 1; $i -le $Parts; $i++) {
        $first = (($i - 1) * $ChunkSize)
        $last  = [Math]::Min(($i * $ChunkSize) - 1, $items - 1)
        ,$Array[$first..$last]
    }

    return ,$result
}

В вашем случае вы можете использовать ее как:

$p = 4  # the number of parts you want
$subArrays = Split-Array $A.ToArray() -Parts $p

или

$k = 4  # the max number items in each part
$subArrays = Split-Array $A.ToArray() -ChunkSize $k
0 голосов
/ 03 мая 2020

Вот функция, которую я придумал, чтобы разделить ваш System.Collections.ArrayList на список вложенных массивов p частей. Он использует System.Collections.Specialized.OrderedDictionary для группировки блоков размером k по index / chunksize, которые затем округляются до ближайшего целого числа, используя System.Math.Floor. Затем он выбирает только группы с ключами от 0 до $Parts.

function Split-ArrayList {
    [CmdletBinding()]
    param (
        # Arraylist to slice
        [Parameter(Mandatory=$true)]
        [System.Collections.ArrayList]
        $ArrayList,
        # Chunk size per part
        [Parameter(Mandatory=$true)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $ChunkSize,
        # Number of parts
        [Parameter(Mandatory=$true)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $Parts
    )

    # Group chunks into hashtable
    $chunkGroups = [ordered]@{}
    for ($i = 0; $i -lt $ArrayList.Count; $i++) {

        # Get the hashtable key by dividing the index by the chunk size
        # Round down to nearest integer using Math.Floor
        [int]$key = [Math]::Floor($i / $ChunkSize)

        # Add new arraylist for key if it doesn't exist
        # ContainsKey is not supported for ordered dictionary
        if ($chunkGroups.Keys -notcontains $key) {
            $chunkGroups.Add($key, [System.Collections.ArrayList]::new())
        }

        # Add number to hashtable
        [void]$chunkGroups[$key].Add($ArrayList[$i])
    }

    # Create nested ArrayList of parts
    $result = [System.Collections.ArrayList]::new()
    for ($key = 0; $key -lt $Parts; $key++) {
        [void]$result.Add($chunkGroups[$key])
    }

    $result
}

Использование:

$A = [System.Collections.ArrayList]::new(1..10)

Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 1 | 
    ForEach-Object { "{ " + ($_ -join ", ") + " }" }

# { 1, 2, 3, 4 }

Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 2 | 
    ForEach-Object { "{ " + ($_ -join ", ") + " }" }

# { 1, 2, 3, 4 }
# { 5, 6, 7, 8 }

Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 3 | 
    ForEach-Object { "{ " + ($_ -join ", ") + " }" }

# { 1, 2, 3, 4 }
# { 5, 6, 7, 8 }
# { 9, 10 }

Примечание: Я действительно не учел случаи, когда вы можете исключить Parts, поэтому я сделал каждый параметр обязательным. Вы можете изменить функцию, чтобы она была более гибкой с различными входами.

...