It's characteristic of the ArrayList class to output the index on .Add(...)
. However, PowerShell returns all output, which will cause it to intermingle the index numbers with the true or other intended output.
My favorite solution is to simply cast the the output from the .Add(...)
method to [Void]
:
function returnAnArray{
$arrayToReturn = [System.Collections.ArrayList]::new()
[Void]$arrayToReturn.Add('logICM_20210222_075234315.txt')
return $arrayToReturn
}
You can also use Out-Null
for this purpose but in many cases it doesn't perform as well.
Another method is to assign it to $null
like:
function returnAnArray{
$arrayToReturn = [System.Collections.ArrayList]::new()
$null = $arrayToReturn.Add('logICM_20210222_075234315.txt')
return $arrayToReturn
}
In some cases this can be marginally faster. However, I prefer the [Void]
syntax and haven't observed whatever minor performance differential there may be.
Note: $null = ...
works in all cases, while there are some cases where [Void]
will not; See this answer (thanks again mklement0) for more information.
An aside, you can use casting to establish the list:
$arrayToReturn = [System.Collections.ArrayList]@()
Update Incorporating Important Comments from @mklement0:
return $arrayToReturn
may not behave as intended. PowerShell's output behavior is to enumerate (stream) arrays down the pipeline. In such cases a 1 element array will end up returning a scalar. A multi-element array will return a typical object array [Object[]]
, not [Collection.ArrayList]
as seems to be the intention.
The comma operator can be used to guarantee the return type by making the ArrayList the first element of another array. See this answer for more information.
Example without ,
:
Function Return-ArrayList { [Collections.ArrayList]@(1,2,3,4,5,6) }
$ArrReturn = Return-ArrayList
$ArrReturn.gettype().FullName
Returns: System.Object[]
Example with ,
:
Function Return-ArrayList { , [Collections.ArrayList]@(1,2,3,4,5,6) }
$ArrReturn = Return-ArrayList
$ArrReturn.gettype().FullName
Returns: System.Collections.ArrayList
Of course, this can also be handled by the calling code. Most commonly by wrapping the call in an array subexpression @(...)
. a call like: $filenames = @(returnAnArray)
will force $filenames
to be a typical object array ([Object[]]
). Casting like $filenames = [Collections.ArrayList]@(returnArray)
will make it an ArrayList.
For the latter approach, I always question if it's really needed. The typical use case for an ArrayList is to work around poor performance associated with using +=
to increment arrays. Often this can be accomplished by allowing PowerShell to return the array for you (see below). But, even if you're forced to use it inside the function, it doesn't mean you need it elsewhere in the code.
For Example:
$array = 1..10 | ForEach-Object{ $_ }
Is preferred over:
$array = [Collections.ArrayList]@()
1..10 | ForEach-Object{ [Void]$array.Add( $_ ) }
Persisting the ArrayList type beyond the function and through to the caller should be based on a persistent need. For example, if there's a need easily add/remove elements further along in the program.
Still More Information:
Notice the Return
statement isn't needed either. This very much ties back to why you were getting extra output. Anything a function outputs is returned to the caller. Return
isn't explicitly needed for this case. More commonly, Return
can be used to exit a function at desired points...
A function like:
Function Demo-Return {
1
return
2
}
This will return 1
but not 2
because Return
exited the function beforehand. However, if the function were:
Function Demo-Return
{
1
return 2
}
This returns 1, 2
.
However, that's equivalent to Return 1,2
OR just 1,2
without Return
Update based on comments from @zett42:
You could avoid the ArrayList behavior altogether by using a different collection type. Most commonly a generic list, [Collections.Generic.List[object]]
. Technically [ArrayList]
is deprecated already making generic lists a better option. Furthermore, the .Add()
method doesn't output anything, thus you do not need [Void]
or any other nullification method. Generic lists are slightly faster than ArrayLists, and saving the nullification operation a further, albeit still small performance advantage.