Koans/Foundations/AboutArrays.Koans.ps1
using module PSKoans [Koan(Position = 113)] param() <# Arrays and Iterable Collections Like many programming languages, PowerShell often uses arrays to keep collections of objects together. Arrays tie in closely with PowerShell's pipeline, which is one way to iterate over a collection with a good deal of efficiency. There are a few 'array-like' collection types available in PowerShell, all of which are rooted in .NET classes and data types, and behave much the same as they do in C# and VB.NET. Arrays in particular have a close relationship with the PowerShell pipeline, which will be covered a shortly. #> Describe 'Arrays' { It 'is useful for grouping related objects and values' { # The comma operator is used to create an array. Spaces are typically ignored. $Ages = 12, 25, 18, 64 <# Individual elements of an array can be accessed with square-bracket index syntax. Arrays are zero-indexed; the first element is at index 0, the second at 1, etc. #> $Ages[0] | Should -Be 12 __ | Should -Be $Ages[3] <# The array subexpression operator @() is used to create an array from multiple values or expressions. Within the parentheses, either commas, semicolons, or even line breaks can be used to divide array elements. Although in many cases in PowerShell an expression that only returns one value will not become an array, this operator forces the value or object to be wrapped in an array. #> $Names = @( 'Steve' 'John'; 'Jaime' # This is a messy way to do things, but it does work 'Abigail', 'Serena', 'Kali' # Having everything on its own line would be much cleaner and is a common usage of this syntax. ) # Where is index 4 in the above array? __ | Should -Be $Names[4] } It 'is a fixed size collection; elements cannot be added or removed' { # Most arrays in PowerShell are fixed size. Elements cannot be directly added or removed. $Ages = 12, 25, 18, 64 { $Ages.Add(59) } | Should -Throw -ExpectedMessage '____' { $Ages.Remove(12) } | Should -Throw -ExpectedMessage '____' } It 'can be created using the addition operator' { <# To add an element to a fixed size array, a new array must be created. PowerShell does this in the background when the addition operator is used. #> $Ages = 12, 25, 18, 64 $Age = __ $Ages = $Ages + $Age # The operation above can be shortened using the Add-and-Assign operator. $Age = __ $Ages += $Age $Ages | Should -Be 12, 25, 18, 64, 42, 59 <# The cost of adding an element to an array in PowerShell like this increases with the size of the array. Each time a new element is added, the array must be copied to a new larger array to accommodate the new values. The result of the operation is another fixed size array. #> } It 'can be joined with another array using the addition operator' { $firstValue = __ $fourthValue = __ $Array = @($firstValue, 2) + @(3, $fourthValue) # A new array is created to hold all of the values. $Array | Should -Be 1, 2, 3, 4 } It 'allows the collection to be split into multiple parts' { $Ages = 11, 18, 25, 74, 19 # An array can be split by assigning it to multiple variables at once: $Jim, $Ashley, $Theresa, $Bob, $Janice = $Ages $Jim | Should -Be 11 __ | Should -Be $Bob # Arrays can be unevenly split by specifying fewer variables. $Jim, $Ashley, $Others = $Ages # What would be stored in $Others? __ | Should -Be $Others <# If you know the contents of the array and want to skip specific elements, you can assign specific elements to $null to discard them. $null is one of PowerShell's automatic variable values, like $true and $false, and cannot be altered. Any data you attempt to assign to it will be ignored. #> $null, $Number1, $Number2 = $Others __ | Should -Be $Number1 } It 'lets you build a subset of the original array' { $Array = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 $Start = __ $Finish = __ # Arrays let you pick a range of indexes to build new arrays $Array[$Start..$Finish] | Should -Be @(6, 7, 8) # You can also select specific index numbers $Index = __ $Array[1, $Index, 4] | Should -Be @(2, 9, 5) } It 'has properties which describe the size of the array' { $Array = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 __ | Should -Be $Array.Count # For fixed size arrays, the Count property is an alias of Length $Array.Count | Should -Be $Array.Length <# More advanced .NET collections do not have a Length property. Count is the more reliable choice. PowerShell adds the Count alias to fixed size arrays to make working with arrays and array-like collections consistent. #> $Array = 1, 2, 3, 4 $List = [System.Collections.Generic.List[Int]]@(1, 2, 3, 4) $List.Count | Should -Be $Array.Count # The List collection used above is covered in more detail in a later Koan. } It 'allows use of negative indexes' { $Array = 1, 2, 3, 4, 5, 6, 7 __ | Should -Be $Array[-1] # What is the -1th item? # Negative numbers can also form a range and extract subsets $Item = __ @( $Item, 5, 6, 7) | Should -Be $Array[-4..-1] $Index = __ $Array[-3, $Index, -6] | Should -Be @(5, 1, 2) # You can make use of this to reverse an entire array $LastIndex = __ # Hint: needs to be a negative number! $Array[-1..$LastIndex] | Should -Be @(7, 6, 5, 4, 3, 2, 1) } It 'does not throw exceptions with invalid indexes' { $Array = 1, 2, 3, 4 # It allows negative indexes, but what about indexes out of range? __ | Should -Be $Array[4] # What about undefined negative indexes? __ | Should -Be $Array[-10] # NOTE: The above will actually throw errors if you have PowerShell running in Strict Mode. } It 'can create be created from a range' { # The .. notation used to reverse an array may be used to array. $Array = 1, 2, 3, 4, 5 $StartIndex = __ $StartIndex..5 | Should -Be $Array } It 'can create an array of letters from a range' { $firstLetter = '__' $lastLetter = '__' if ($PSVersionTable.PSEdition -eq 'Core') { # PowerShell Core uses .. between the letters to create an array. $letters = $firstLetter..$lastLetter $letters | Should -Be 'a', 'b', 'c', 'd' } else { # Windows PowerShell 5 and below have to work a lot harder to achieve the same thing. $letters = ([Int][Char]$firstLetter)..([Int][Char]$lastLetter) -as [Char[]] $letters | Should -Be 'a', 'b', 'c', 'd' } } It 'is usually of type Object[]' { <# Arrays in PowerShell are created with the type Object[]. An array of Objects. The Object type can hold anything at all. A numeric value, a character, a Process, and so on. #> $Numbers = 1, 2, 3, 4 '____' | Should -Be $Numbers.GetType().Name $Strings = 'first', 'second', 'third' [____] | Should -Be $Strings.GetType() $Processes = Get-Process '____' | Should -Be $Processes.GetType().Name <# The base type of Object[], Char[], and other fixed size array types is the System.Array type, or [Array]. The [Array] type describes the Length property (aliased to Count), as well as other methods which can be used to work with the array. The available methods can be seen with Get-Member: Get-Member -InputObject @() For example, each array has a Contains method. #> $____ -eq $Numbers.Contains(3) | Should -BeTrue # The Contains method is case sensitive for arrays containing strings. $____ -eq $Strings.Contains('first') | Should -BeTrue $____ -eq $Strings.Contains('First') | Should -BeTrue # PowerShell's -contains operator is not case sensitive. $Strings -contains '____' | Should -BeTrue $Strings -contains '____' | Should -BeTrue } It 'can be cast to a specific collection type' { [string[]] $Array = 1, 2, 3, 4, 5 # We started with numbers... what do we have after the array is created? [____] | Should -Be $Array[0].GetType() [____] | Should -Be $Array.GetType() } } |