Powershell - Looping through objects in batches of 3 - powershell

I have an object which contains 7 items.
$obj.gettype().name
Object[]
$obj.length
7
I want to loop through in batches of 3. I do NOT want to use the modulus function, I actually want to be able to create a new object with just the 3 items from that batch. Pseudo code:
$j=0
$k=1
for($i=0;$i<$obj.length;$i+=3){
$j=$i+2
$myTmpObj = $obj[$i-$j] # create tmpObj which contains items 1-3, then items 4-6, then 7 etc
echo "Batch $k
foreach($item in $myTmpObj){
echo $item
}
$k++
}
Batch 1
item 1
item 2
item 3
Batch 2
item 4
item 5
item 6
Batch 3
Item 7
Regards,
ted

Your pseudo code is almost real. I have just changed its syntax and used the range operator (..):
# demo input (btw, also uses ..)
$obj = 1..7
$k = 1
for($i = 0; $i -lt $obj.Length; $i += 3) {
# end index
$j = $i + 2
if ($j -ge $obj.Length) {
$j = $obj.Length - 1
}
# create tmpObj which contains items 1-3, then items 4-6, then 7 etc
$myTmpObj = $obj[$i..$j]
# show batches
"Batch $k"
foreach($item in $myTmpObj) {
$item
}
$k++
}
The output looks exactly as required.

See if this one may work as required (I assume your item n is an element of $obj)
$obj | % {$i=0;$j=0;$batches=#{}}
if($i!=3 and $batches["Batch $j"]) { $batches["Batch $j"]+=$_; $i+=1 }
else {$i=1;$j+=1;$batches["Batch $j"]=#($_)}
} {$batches}
Should return an HashTable ($batches) with keys such as "Batch 1", "Batch 2", ... each key related to an array of three items.

Related

How to Iterate through an index of n using different index of p

I am doing this in PowerShell, although the question isn't tied to a language.
lets say that I have an indexed array of size n called accounts, and another indexed array of size p called rows. I want to go through each of the items in row and use an account to do something. In my real world example, I have excel rows and I need to log into accounts in the accounts array in a round-robin fashion. the size of these arrays can be anything from 1 to n, and they will very likely not be the same size as the other. What math problem can I use to ensure that, regardless of the size of the array, I get the iterations below (assume $rows.Count is 500 and $accounts.Count is 12:
rows[1] - accounts[1]
rows[2] - accounts[2]
rows[3] - accounts[3]
rows[4] - accounts[4]
rows[5] - accounts[5]
rows[6] - accounts[6]
rows[7] - accounts[7]
rows[8] - accounts[7]
rows[9] - accounts[8]
rows[10] - accounts[9]
rows[11] - accounts[10]
rows[12] - accounts[11]
rows[13] - accounts[12]
rows[14] - accounts[1]
rows[15] - accounts[2]
rows[16] - accounts[3]
rows[17] - accounts[4]
My attempts have landed on this so far:
for ($i = 0; $i -lt $rows.Count; $i++) {
$k = 0
$j = $accounts.Count
if ($i -le $j) {
$k = $j
}
else {
$k = $i % $j
}
$rows[$i] - $accounts[$k]
}
I think that modulus is the key, but I can't seem to finish the equation.
Indeed, using %, the modulus operator, is key; a PowerShell-idiomatic solution (it simply prints the paired array elements):
$rows = 1..500
$accounts = 1..12
$i = 0
$rows.ForEach({ '{0} - {1}' -f $_, $accounts[$i++ % $accounts.Count] })
Note that array indices in PowerShell / .NET are 0-based.

Processing items within a powershell array - multiple items

I have been reading about arrays in powershell and hash tables, I know the basic workings of an array and how to use foreach loop to get items within the array, my challange here is slightly different. I would like to pay what I call a multi dimension array to a script, and process the items contained within the array.
What is my setup.
$x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
$k = 'serverid','servername','locationid','appid' # key names correspond to data positions in each array in $x
$h = #{}
For($i=0;$i -lt $x[0].length; $i++){
$x |
ForEach-Object{
[array]$h.($k[$i]) += [string]$_[$i]
}
}
What am i trying to achieve ?
I am trying to achieve the structure of a database table within powershell. So literally treating each array item as a row.
So for example
(1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
could be thought of as a table like below
enter image description here
I then want to loop for each item in the array to get the values, similar to the below example
[0].serverid = 1, [0].servername = server1, [0].locationid = 3, [0].applicationID = 1
[1].serverid = 4, [1].servername = server2, [1].locationid = 6, [1].applicationID = 2
what have I done ?
$x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
$k = 'serverid','servername','locationid','appid' # key names correspond to data positions in each array in $x
$h = #{}
For($i=0;$i -lt $x[0].length; $i++){
$x |
ForEach-Object{
[array]$h.($k[$i]) += [string]$_[$i]
}
}
$x
for ($i = 0; $i -lt $x.Count; $i++)
{
$myserverid = $x[$i][0]
$myservername = $x[$i][1]
$mylocationid = $x[$i][2]
$myappid = $x[$i][3]
write-host $myserverid
}
The Issues
If I set the following $x = (1,"Server1",3,1), then the loop is somewhat incorrect which is why I think the approach is wrong (more than one item works i.e $x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)). The loop only works if you have more than one item within the array, hence why I want to re-examine the way the loop works.
Thanks in advance
Your approach relies on a nested (jagged) array: That is, you have an array of subarrays, each of which represents the tuple of values you want to assign to properties.
If there's only one subarray, you must create the nested array explicitly, using the unary form of , the array constructor operator:
# Construct a 1-element array that contains the 4-element subarray.
$x = , (1,"Server1",3,1)
With two or more, subarrays, you implicitly get a nested array:
# Construct a 3-element array, each element of which contains a 4-element subarray.
$x = (1,"Server1",3,1), (4,"Server2",6,2), (3,"Server3",4,3)
Note that in PSv5+ you could use a custom class to solve your problem:
class Custom {
[int] $serverid; [string] $servername;[int] $locationid; [int] $appid
Custom($propValueArray) {
$this.serverid = $propValueArray[0]; $this.servername = $propValueArray[1]; $this.locationid = $propValueArray[2]; $this.appid = $propValueArray[3]
}
}
# Use an array cast to construct [Custom] instances.
# Note the need for (...) around the array, because casts have high
# precedence in PowerShell.
[Custom[]] ((1,"Server1",3,1), (4,"Server2",6,2), (3,"Server3",4,3))
This would allow for processing such as:
# Construct all objects
$objects = [Custom[]] ((1,"Server1",3,1), (4,"Server2",6,2), (3,"Server3",4,3))
# Process each object.
foreach ($object in $objects) {
($myserverid = $object.serverid) # assign a property to a var; `()` also outputs
# ...
}

powershell execute math on array elements

I'm looking to perform math on two arrays but i'm always ending up executing on the arrays itself and not it elements. how do i call each element from both arrays and perform math on them one by one?
$array1 = (1,2,3)
$array2 = (1,2,3)
$do | % {$array1 + $array2}
this adds the arrays together as in:
1
2
3
1
2
3
but the result i am looking for is the following:
2
4
6
how do i have to go about this?
One way would be to use for like this:
$array1 = (1,2,3)
$array2 = (1,2,3)
for ($i = 0; $i -lt $array1.Length; $i++){
$array1[$i] + $array2[$i]
}
Output:
2
4
6

Powershell loop with numbers to alphabet

I need help with the following:
Create a for loop based on the conditions that the index is initialized to 0, $test is less than 26, and the index is incremented by 1
For each iteration, print the current letter of the alphabet. Start at the letter A. Thus, for each iteration, a single letter is printed on a separate line.
I am not able to increment the char each time the loop runs
for ($test = 0; $test -lt 26; $test++)
{
[char]65
}
I have tried multiple attempts with trying to increment the char 65 through 90 with no success.
Is there an easier way to increment the alphabet to show a letter for each loop that is ran?
You can sum your loop index with 65. So, it'll be: 0 + 65 = A, 1 + 65 = B ...
for ($test = 0; $test -lt 26; $test++)
{
[char](65 + $test)
}
PS2 to PS5:
97..(97+25) | % { [char]$_ }
Faster:
(97..(97+25)).ForEach({ [char]$_ })
PS6+:
'a'..'z' | % { $_ }
Faster:
('a'..'z').ForEach({ $_ })
The following example does not assume 'A' is 65 and also allows you to change it to whatever starting drive you desire. For example, to start with 'C' and go to 'Z':
$start = 'C'
for ($next = 0; $next -lt (26 + [byte][char]'A' - [byte][char]$start); $next++) {
[char]([byte][char]$start + $next)
}
Here's a way to find the first available drive. It checks drives E to Z, and stops on the first available one:
101..(97+25) | % { if(!( get-psdrive ([char]$_ ) -ea 0 ) ) {$freedrive = ([char]$_ ); break} }
$freedrive

Building automatic strings based on a variable

I have a variable called: $backendSubnet
This variable currently contains 4 entries, when I do $backendSubnet.Count it returns '4'
This number of entries will change each time the script is run. What I need to do it automatically break out (based on the number of entries) in this instance there's 4 - to be used in another CmdLet, see.....
-Subnet $backendSubnet1,$backendSubnet2,$backendSubnet3,$backendSubnet2
I need to automate breaking this out arranged like this above.
I have tried the following, bit I think I am on the wrong track:
$max = $backendSubnet.Count -1;0..$max | % {$backendSubnetArray += $backendSubnet[$_]}
I would suggest initializing a new array to a predefined size, then copy N elements from the $backendSubnet into the new array. Then rinse and repeat.
for ($i = 0; $i -lt $backendSubnet.Count; $i += $numToCopy)
{
$numToCopy = [Math]::Min($backendSubnet.Count - $i, $max)
$subset = new-object object[] $numToCopy
[Array]::Copy($backendSubnet, $i, $subset, 0, $numToCopy)
SomeCmdlet -Subnet $subset
}