Reputation: 63
Hello everyone hope you are all doing great! been searching but cannot get it right :( could it be possible for you to help me, please? Need to split an array into 5 arrays with equal length, for example.
$MainArray = @(1,2,3,4,5,6,7,8,9,10,11)
Result:
array1 = 1,2,3
array2 = 4,5
array3 = 6,7
array4 = 8,9
array5 = 10,11
Each array as even as possible (order doesn't matters) has this and it splits but not as even as I would like to.
Currently, I have this (searched on the internet already)
function Split-Array {
[CmdletBinding()]
param(
[Object] $inArray,
[int]$parts
)
if ($inArray.Count -eq 1) { return $inArray }
$PartSize = [Math]::Ceiling($inArray.count / $parts)
$outArray = New-Object 'System.Collections.Generic.List[psobject]'
for ($i = 1; $i -le $parts; $i++) {
$start = (($i - 1) * $PartSize)
$end = (($i) * $PartSize) - 1
if ($end -ge $inArray.count) {$end = $inArray.count - 1}
$outArray.Add(@($inArray[$start..$end]))
}
return , $outArray
}
Split-array -inArray $MainArray -parts 5
This function splits the $MainArray
into 5 arrays but not as even, the result is:
array1 = 1,2,3
array2 = 4,56
array3 = 7,8,9
array4 = 10,11
array5 = 11
It even errors adding 11 into 2 arrays. My brain is burned at this moment, haha any help would be much appreciated. thanks!
Upvotes: 1
Views: 1079
Reputation: 13
My use-case for this is populating a hash with some unknown number of values from an array where I need a fixed size array value for the hash entries based on other criteria in my hash's values. Lets say my array turns out to have 3422 elements and I need 100 per hash value plus whatever's left over for the last element added to the hash. Then: [Math]::Floor(3422/100) will give you the number of hash elements needed. I use 3 counters: $i, $j and $k
For instance:
$myArray = (get-<whatever> |select -exp Name)
$mySizeLimit = 100
$total = $myArray.count
$buckets = [math]::Floor($total/$mySizeLimit)
$myWrkHash = @{}
$j = 0; $k = 0;
for ($i = 0; $i -LE $buckets; $i++) {
if($i -LT $buckets) {
$k = $j + ($mySizeLimit - 1)
$myWrkHash.Add($i, $myArray[$j..$k])
$j+=$mySizeLimit
} elseif($i -EQ $buckets) {
$k = $total - 1
$myWrkHash.Add($i, $myArray[$j..$k])
}
}
Upvotes: 0
Reputation: 437208
To perform the element distribution as requested - with extra elements getting added to the initial output arrays - use the following.
function Split-Array {
[CmdletBinding()]
param(
[object[]] $inArray,
[int] $parts
)
[int] $partSize = [Math]::Floor($inArray.count / $parts)
if ($partSize -eq 0) { throw "$parts sub-arrays requested, but the input array has only $($inArray.Count) elements." }
$extraSize = $inArray.Count - $partSize * $parts
$offset = 0
foreach ($i in 1..$parts) {
, $inArray[$offset..($offset + $partSize + [bool] $extraSize - 1)]
$offset += $partSize + [bool] $extraSize
if ($extraSize) { --$extraSize }
}
}
Note:
[bool]
casts are used as a convenient shortcut to map nonzero values to 1
and zero to 0
, via using the resulting [bool]
in the context of calculations.
..
- the range operator - is used to extract array slices from the input array, and also as a simple way to loop $parts
times via a foreach
loop.
,
- the array constructor operator - is used in its unary form to output each array slice as a whole - see this answer for an explanation.
Sample call, which uses ConvertTo-Json
to visualize the results:
Split-array -inArray (1..11) -parts 5 |
ConvertTo-Json
Output (5 arrays with 2-3 elements each):
[
[
1,
2,
3
],
[
4,
5
],
[
6,
7
],
[
8,
9
],
[
10,
11
]
]
Upvotes: 3
Reputation: 4694
If you keep track of the arrays created, you should be able to get the results you're after:
Function Split-Array {
Param(
[object]$InputObject,
[int]$Chunks
)
$track = 1
while ($InputObject.Count -gt 0 -and $track -le $Chunks) {
$chunk_size = [Math]::Min($InputObject.Count, [Math]::Ceiling($InputObject.Count / ($Chunks - $track + 1)))
$chunk = $InputObject[0..($chunk_size - 1)]
$InputObject = $InputObject[$chunk_size..($InputObject.Count - 1)]
,$chunk
$track++
}
}
The while loop starts, and it will keep executing as long as either of these conditions are met:
$array.Count -gt 0
: The count of elements in $array is greater than
0. This means that there are still elements in $array that need to be split into separate arrays.
$arrayIndex -le $arrayCount
: The number of arrays created so far is
less than or equal to $arrayCount
. This means that you haven't
created the desired number of arrays yet.
Upvotes: 1