I encountered some issue in converting my existing vbs script to PowerShell script. I have illustrate here with some dummy codes instead of my original code. In example 1, I only have 1 set of elements in the array, upon return the array variable to the function, it will only display P.
However in example 2, where I have 2 set of elements in the array, upon return the array variable to the function, it will display the elements properly.
If you print the array inside the function in example 1 and 2. There isn't any issue in getting the results.
I have googled and not able to find any solution to it. Many thanks in advance for the kind help.
Example 1:
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return $array1
}
$array2 = testArray
Write-Host $array2[0][1]
Result is "P".
Example 2:
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
$array1 += ,#("Orange","Pineapple")
return $array1
}
$array2 = testArray
Write-Host $array2[0][0]
Result is "Apple".
PowerShell unrolls arrays returned from a function. Prepend the returned array with the comma operator (,, unary array construction operator) to wrap it in another array, which is unrolled on return, leaving the nested array intact.
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return ,$array1
}
when you declare single line array like
$array1 = "Apple","Banana"
when you call :
$array1[0][1]
this will happen :
this code
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return $array1
}
$array2 = testArray
Write-Host $array2[0][1]
exact the same of this:
$array1 = "Apple","Banana"
but when you declare 2 row of array like :
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
$array1 += ,#("Orange","Pineapple")
return $array1
}
$array2 = testArray
Write-Host $array2[0][0]
this will happen :
if you need apple in your first code just call array[0] not array[0][0]. array[0][0] return char for you.
sorry for my bad english i hope you understand
$array1 inside your function TestArray is always of rank 1, fixed, and has never an element with type array. Check how a + is defined on arrays.
In this case you want to use an ArrayList:
$array1=[Collections.ArrayList]::new(10) # 10 is capacity
After that you can use the Add function. Even with arrays. And this time they will not be flattened, as was the case with the + array operator.
Other dynamic collection types also exist. But this one looks ok for many purposes.
Related
I have 2 arrays like this:
$array1 = #('Item10', 'Item20', 'Item30', 'Item40')
$array2 = #('Item1', 'Item3')
I would like to have my final array like this:
$arrayfinal = #('Item30', 'Item40')
meaning: find 'like' Item1 from array2 in array1, so remove it !
I tried: with the '-like' operator, the '-ne' operator, tried to add '*' and use the 'like' operator but could not find what I want.
Thanks for your help
You need to test each value in $array1 against each possible prefix from $array2 until you get a match (or not) - in other words, nested filters.
My preferred approach is to nest .Where({...}, 'First') inside Where-Object:
$arrayfinal = $array1 |Where-Object {$item = $_; -not $array2.Where({$item -like "${_}*"}, 'First')}
The 'First' mode will make .Where() return as soon as the first item satisfies the condition, thereby not needlessly going through all of $array2 on each iteration.
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]
}
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)]
}
I encountered some issue in converting my existing vbs script to PowerShell script. I have illustrate here with some dummy codes instead of my original code. In example 1, I only have 1 set of elements in the array, upon return the array variable to the function, it will only display P.
However in example 2, where I have 2 set of elements in the array, upon return the array variable to the function, it will display the elements properly.
If you print the array inside the function in example 1 and 2. There isn't any issue in getting the results.
I have googled and not able to find any solution to it. Many thanks in advance for the kind help.
Example 1:
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return $array1
}
$array2 = testArray
Write-Host $array2[0][1]
Result is "P".
Example 2:
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
$array1 += ,#("Orange","Pineapple")
return $array1
}
$array2 = testArray
Write-Host $array2[0][0]
Result is "Apple".
PowerShell unrolls arrays returned from a function. Prepend the returned array with the comma operator (,, unary array construction operator) to wrap it in another array, which is unrolled on return, leaving the nested array intact.
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return ,$array1
}
when you declare single line array like
$array1 = "Apple","Banana"
when you call :
$array1[0][1]
this will happen :
this code
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
return $array1
}
$array2 = testArray
Write-Host $array2[0][1]
exact the same of this:
$array1 = "Apple","Banana"
but when you declare 2 row of array like :
function testArray {
$array1 = #()
$array1 += ,#("Apple","Banana")
$array1 += ,#("Orange","Pineapple")
return $array1
}
$array2 = testArray
Write-Host $array2[0][0]
this will happen :
if you need apple in your first code just call array[0] not array[0][0]. array[0][0] return char for you.
sorry for my bad english i hope you understand
$array1 inside your function TestArray is always of rank 1, fixed, and has never an element with type array. Check how a + is defined on arrays.
In this case you want to use an ArrayList:
$array1=[Collections.ArrayList]::new(10) # 10 is capacity
After that you can use the Add function. Even with arrays. And this time they will not be flattened, as was the case with the + array operator.
Other dynamic collection types also exist. But this one looks ok for many purposes.
I wondered if anyone could shed some light on the issue I am facing when returning values from a multidimensional array through a function:
$ArrayList = #()
function MultiDimensionalArrayTest
{
param(
[array]$ArrayList
)
for($i = 0; $i -lt 1; $i++)
{
$ArrayModify += ,#("Test", "Test")
}
return $ArrayModify
}
$ArrayModify = MultiDimensionalArrayTest
foreach ($item in $ArrayModify)
{
Write-Host $item[0]
}
When the loop is executed once the values returned are:
T
T
However if the for statement is lopped twice, the values returned are:
Test
Test
My aim is to retrieve x amount of values "Test" from the Write-Host $item[0] regardless of how many times the statement is executed
It appears that if two or more rows are captured and returned in the $ArrayModify array, the value is a system.object[], however if looped once, the value "Test, Test" is captured and when Write-Host $item[0] is executed, it will print T.
Any advice would be greatly appreciated.
Not the cleanest way of dealing with it but you need to prevent PowerShell from unrolling the single element array into an array with two elements.
function MultiDimensionalArrayTest{
$ArrayModify = #()
for($i = 0; $i -lt 1; $i++){
$ArrayModify += ,#("Test$i", "Test$i$i")
}
,#($ArrayModify)
}
Using the above function will get the desired output I believe. ,#($ArrayModify) ensures that the array is returned and not unrolled into its elements as you saw above.
$ArrayList = #()
$ArrayList = MultiDimensionalArrayTest
foreach ($item in $ArrayList){$item[0]}
Giving the output for $i -lt 1 in the loop
Test0
Giving the output for $i -lt 2 in the loop
Test0
Test1
Your Output
Concerning your output from your example with $i -lt 1 PowerShell is unrolling the array into a single dimension array with 2 elements "Test" and "Test". You are seeing the letter "T" since all strings support array indexing and will return the character from the requested position.
Other issues with code
Not to beat a dead horse but really look at the other answers and comments as they provide some tips as to some coding errors and anomalies of the code you presented in the question.
First of all I notice several mistakes in your code.
This line $ArrayList = #() is useless since you don't use the $ArrayList variable afterwards.
Regarding the MultiDimensionalArrayTest function, you declared an $ArrayList argument but you never use it in the function.
Finally when this line makes no sense $ArrayModify = MultiDimensionalArrayTest = $item, you probably meant $ArrayModify = MultiDimensionalArrayTest.
This is not a complete answer to your question, since I am not sure what you are trying to achieve, but take a look at this line:
$ArrayModify = MultiDimensionalArrayTest = $item
This makes no sense, since you are calling the function MultiDimensionalArrayTest and passing two arguments to it, which are "=" (powershell assumes this is a string) and $item (null object). Then you assign whatever is returned to $ArrayModify.
The reason "T" is outputted, is because you are outputting the first element of what is at the moment a string. "Test" is outputted when $item is an array of strings.