How to get 2 dimensional array with foreach in PowerShell? - arrays

I have 2 dimension array. I would like to get each value of array.
I tried this, but each array in $Name has all the array in $Date. But my expectation first item in $Name equal to first item in $Date.
This is my expectation result:
A\11
B\12
C\13
$Name = #("A", "B", "C") #the size of this array not fixed
$Date = #("11", "12", "13") #the size of this array not fixed
foreach ($na in $Name)
{
foreach ($dt in $Date)
{
$NameAndDate = "$na\$dt"
Write-Host $NameAndDate
}
}
but from the code above I got this result
A\11
A\12
A\13
B\11
B\12
B\13
C\11
C\12
C\13
Anyone can help, please. Thank you

When combining two arrays, both having a non-fixed number of elements, you need to make sure you do not index beyond any of the arrays indices.
The easiest thing here is to use an indexed loop, where you set the maximum number of iterations to the minimum number of array items:
$Name = "A", "B", "C" # the size of this array not fixed
$Date = "11", "12", "13" # the size of this array not fixed
# make sure you do not index beyond any of the array indices
$maxLoop = [math]::Min($Name.Count, $Date.Count)
for ($i = 0; $i -lt $maxLoop; $i++) {
# output the combined values
'{0}\{1}' -f $Name[$i], $Date[$i]
}
Output:
A\11
B\12
C\13

Try this
$Name = #("A", "B", "C") #the size of this array not fixed
$Date = #("11", "12", "13") #the size of this array not fixed
foreach ($i in 0..($Name.Count -1)) {
write-host ($Name[$i] + "\" + $Date[$i])
}

Related

Array of Arrays - Print Names of Inner Arrays - Powershell

I have two arrays in one outer array
$array1 = #("a", "b")
$array2 = #("c", "d")
$arrayAll = $array1, $array2
I now want to print the names "array1" , "array2" in the foreach-loop
foreach($array in $arrayAll){
Write-Host $array
}
Which returns
a b
c d
with the result that i want would be
$array1
$array2
While $allArray.Count still returns 2 elements. How do i print just the Array names and not what is in the Arrays ?
Probably not the answer you expect but this is a good place for using a hash table:
$hashAll = [ordered]#{}
$hashAll['array1'] = #("a", "b")
$hashAll['array2'] = #("c", "d")
foreach($key in $hashAll.Keys)
{
"This is array: $key"
$hashAll[$key]
}

Powershell use values of one array as headings for another array

I have two arrays in Powershell:
$headings = ['h1', 'h2']
$values = [3, 4]
It is guaranteed that both arrays have the same length. How can I create an array where the values of $headings become the headings of the $values array?
I want to be able to do something like this:
$result['h2'] #should return 4
Update:
The arrays $headings and $values are of type System.Array.
As stated above you'll need a PowerShell hashtable. By the way array in PowerShell are defined via #(), see about_arrays for further information.
$headings = #('h1', 'h2')
$values = #(3, 4)
$combined = #{ }
if ($headings.Count -eq $values.Count) {
for ($i = 0; $i -lt $headings.Count; $i++) {
$combined[$headings[$i]] = $values[$i]
}
}
else {
Write-Error "Lengths of arrays are not the same"
}
$combined
Dumping the content of combined returns:
$combined
Name Value
---- -----
h2 4
h1 3
Try something like this :
$hash = [ordered]#{ h1 = 3; h2 = 4}
$hash["h1"] # -- Will give you 3
## Next Approach
$headings = #('h1', 'h2') #array
$values = #(3, 4) #array
If($headings.Length -match $values.Length)
{
For($i=0;$i -lt $headings.Length; $i++)
{
#Formulate your Hashtable here like the above and then you would be able to pick it up
#something like this in hashtable variable $headings[$i] = $values[$i]
}
}
PS: I am just giving you the logical headstart and helping you with the hashtable part. Code is upto you.

Split an array of strings in to chunks of a maximum size

I'm attempting to ensure an array of unknown length is split in one-or-more arrays with a maximum of 20 elements.
I've searched around and found several answers for similar questions based on arrays containing number sequences (or maybe I'm just missing something), but nothing for an array of strings.
I've come up with a solution, but it seems a little convoluted and I feel it could probably be better.
For example, take this array -
$metricDefinitionsHash= [ordered]#{"this one" = "111"; "that one" = "222"; "another one" = "333"}
And for the sake of this example, that's say I want only a maximum of two elements -
$metricsQueryParts = #()
$counter = 0
$metricDefinitionsHash.Keys | ForEach-Object {
$index = [System.Math]::Floor($counter / 2)
if ($metricsQueryParts.Length -eq $index)
{
$metricsQueryParts += ""
$metricsQueryParts[$index] = #()
}
$metricsQueryParts[$index] += $_
$counter++
}
So now I have an array of arrays -
#(#("this one", "that one"), #("another one"))
But... Can I achieve my goal in a more efficient way?
Use a for loop, the range operator (..), and the unary array construction operator (,):
[array]$keys = $metricDefinitionsHash.Keys
$size = 3
$metricsQueryParts = #()
for ($i=0; $i -lt $keys.Count; $i+=$size) {
$metricsQueryParts += ,$keys[$i..($i+$size-1)]
}
[array]$keys casts the key/value collection .Keys to a generic array (so that the index operator can be used on it).
The expression $i..($i+$size-1) gives you the indexes from $i up to the index before $i+$size, i.e. the next $size elements from the array starting at position $i. If there are less than $size elements the expression will give just the remaining number of elements.
The unary array construction operator ensures that $keys[...] is appended to $metricsQueryParts as a nested array instead of just concatenating the two arrays.
I really like Ansgar's solution but the keys collection isn't an array and as such you can't use the array range syntax. Keys is an OrderedDictionaryKeyValueCollection. I have used out-string -stream to force the OrderedDictionaryKeyValueCollection to an array.
$keys = $metricDefinitionsHash.Keys | out-string -stream
$size = 2
$metricsQueryParts = #()
for ($i=0; $i -lt $keys.Count; $i+=$size) {
$metricsQueryParts += ,$keys[$i..($i+$size-1)]
}

How to combine every element in an array with every element in multiple other arrays in Powershell

In Powershell, I am trying to combine the elements of several arrays to create an array of unique strings. I need to combine every element from each array with every element in the other arrays. It is difficult to concisely explain what I mean, so it may be easier to show.
I start with a 2d-array that looks something like this:
$array = #('this', ('A','B','C'), ('1','2','3','4'), 'that')
I need to create an array, whose contents will look like this:
thisA1that
thisA2that
thisA3that
thisA4that
thisB1that
thisB2that
thisB3that
thisB4that
thisC1that
thisC2that
thisC3that
thisC4that
The length and number of arrays in the original array are variable, and I don't know the order of the items in the original array.
So far, I've tried a few methods, but my logic has been wrong. Here was my first attempt at a solution:
$tempList = #()
#get total number of resources that will be created
$total = 1
for($i=0; $i -lt $array.Count; $i++){$total = $total * $array[$i].Count}
# build each resource from permutations of array parts
for ($i = 0; $i -lt $array.Count; $i++)
{
for ($j = 0; $j -lt $total; $j++)
{
$tempList += #('')
$idx = $total % $array[$i].Count
# item may either be string or an array. If string, just add it. If array, add the item at the index
if ($array[$i] -is [array]){ $tempList[$j] += $array[$i][$idx] }
else { $tempList[$j] += $array[$i] }
}
}
In this example, my logic with the modulus operator was wrong, so it would grab the only the first index of each array every time. Upon further consideration, even if I fix the modulus logic, the overall logic would still be wrong. For example, if the second two arrays were the same size, I would get 'A' paired with '1' each time, 'B' with '2', etc.
I'm sure there is a way to do this, but I simply can't seem to see it.
I think the answer's to use recursion so you can handle the fact that the array of arrays can be any length. This recursive function should:
take the first array from the array-of-arrays
loop through each item in that first array
if the first array is also the last array, just return each item.
if there are more arrays in the array-of-arrays then pass the remaining arrays to the recursive function
for each result from the recursive function, prefix the return value with the current item from the first array.
I think the code explains itself better than the above:
function Combine-Array {
[CmdletBinding()]
Param (
[string[][]]$Array
)
Process {
$current = $Array[0]
foreach ($item in $current) {
if ($Array.Count -gt 1) {
Combine-Array ([string[][]]#($Array | Select -Skip 1)) | %{'{0}{1}' -f $item, $_}
} else {
$item
}
}
}
}
Combine-Array #('this', ('A','B','C'), ('1','2','3','4'), 'that')
You can write pipeline function, which would add one more subarray into the mix. And then you call it as many times as many subarrays you have:
function CartesianProduct {
param(
[array] $a
)
filter f {
$i = $_
$a[$MyInvocation.PipelinePosition - 1] | ForEach-Object { $i + $_ }
}
Invoke-Expression ('''''' + ' | f' * $a.Length)
}
CartesianProduct ('this', ('A','B','C'), ('1','2','3','4'), 'that')

Array to read different values

How can I input multiple values in PowerShell and have those values stored in a variable?
For example:
$value = Read-Host "Enter the value's" #I need 15 values to be entered.
And then recall them e.g:
$value[0] = 1233
$value[1] = 2345
To do this you could declare an array #() and then use a loop and the addition operator to add items to the array (stopping when a blank value is submitted):
$values = #()
Do{
$value = read-host "Enter a value"
if ($value) {$values += $value}
}Until (-not $value)
You can then retrieve values as you described via the index with square brackets []:
$values #returns all values
$values[3] #returns the fourth value (if you entered four or more)
Beware that arrays start from 0, so the first item is [0], second is [1] etc. With PowerShell you can also use negative numbers to work through the array backwards, so [-1] is the last item, [-2] the second to last, etc.
Stores the readin values in an array:
$values = #()
$i = $null
while ($i -ne "q") {
if ($i -ne $null) {
# Attach value to array
$values += $i
}
$i = Read-Host "Enter value (stop with q)"
}
# Print each value in a seperate line
$values | % { Write-Host $_}
# Print type -> to visualize that it is an array
$values.GetType()
# Several values can be retrieved via index operator
$values[0]

Resources