DEV Community

Nathan Windisch
Nathan Windisch

Posted on

Supercharge Your Arrays in PowerShell ⚡

PowerShell has many different types of arrays. The default type of array @() has a fixed collection size. This means that attempting to add additional items to the array fails:

$MyArray = @("hello world")
$MyArray.Add("test")

# MethodInvocationException:
# Exception calling "Add" with "1" argument(s):
# "Collection was of a fixed size."
Enter fullscreen mode Exit fullscreen mode

While one can append items to a collection of a fixed size with the += syntax, this actually creates a copy of the object with the additional values. This can be bad for larger scripts, due to the increased memory consumption that this causes. Additionally, one cannot remove items from a standard array either:

$MyArray = @("hello world")
$MyArray += "test"
$MyArray
# hello world
# test
$MyArray -= "test"
# InvalidOperation: Method invocation failed because [System.Object[]]
# does not contain a method named 'op_Subtraction'.
Enter fullscreen mode Exit fullscreen mode

Luckily, .NET has a class that we can use called List, found in the System.Collections.Generic namespace. These Lists allow you to add and remove items at will, making them perfect for scripts which require job tracking, or run in parallel.

Here are some examples of how to create a new instance of the class:

$MyList = [System.Collections.Generic.List[String]]::new()

# Note that you don't actually need the "System." part of the
# function call:
$MyShorterList = [Collections.Generic.List[String]]::new()

# Also, if you add the Collections.Generic namespace to your 
# instance, you can remove the most of the path entirely:
using namespace System.Collections.Generic
$MyShortestList = [List[String]]::new()


# You can use any type (int, char, bool, String, Hashtable, 
# PSCustomObject, etc) as part of your list, and all newly
# added items will be cast to that type (if possible)
$MyCharList = [List[char]]::new()
$MyCharList.Add(104)
$MyCharList.Add(105)
$MyCharList
# h
# i

$MyIntList = [List[int]]::new()
$MyIntList.Add("hi")
# MethodException:
# Cannot convert value "hi" to type "System.Int32".
# Error: "The input string 'hi' was not in a correct format."
Enter fullscreen mode Exit fullscreen mode

As I've shown, you are able to easily add new items to the list. But what about removing? Here's a few examples:

# First, let's set up an example integer list and populate it with 
# the numbers 0 to 6
$MyIntList = [List[int]]::new()
0..6 | ForEach-Object { $MyIntList.Add($_) }

# To remove a specific item (provided you have an exact copy), use
# .Remove. Note that this method return with if the removal was
# successful or not
$MyIntList.Remove(1)
# True
$MyIntList
# 0
# 2
# 3
# 4
# 5
# 6
$MyIntList.Remove(1)
# False

# To remove an item via it's index, use .RemoveAt
# Note that the index starts at 0
$MyIntList.RemoveAt(3)
$MyIntList
# 0
# 2
# 3
# 5
# 6

# To remove all items which match a specific function, use a
# Predicate and .RemoveAll

# This is a Predicate, which returns all items it's provided with
# that return true based on it's expression.
# Note that you will need to use the same type in your Predicate as
# you did for your List
$OddNumbers = [Predicate[int]]{ param($i) $i % 2 -eq 1 }
# This method returns the amount of items removed
$MyIntList.RemoveAll($OddNumbers)
# 2
$MyIntList
# 0
# 2
# 6

# Finally, you can use .RemoveRange to, well, remove a range of
# items. Note that the first argument is the starting index, the
# second argument is the amount of items you wish to remove (inc
# (the starting index, so 0 would remove nothing and 1 would
# remove only the item selected, similar to .RemoveAt)
$MyIntIndex.RemoveRange(1, 2)
$MyIntIndex
# 0
Enter fullscreen mode Exit fullscreen mode

I hope this has helped you understand more about System.Collection.Generics.List[T]. Please let me know if there are any other topics you'd like me to cover! :)

Top comments (0)