Thursday, September 8, 2016

Arrays and Indexers in PowerShell



Today's post is about Arrays and Indexers in PowerShell. Here below you will find a very easy to follow program, that demonstrate arrays and indexer, by implementing some simple tasks that will make you grasp the idea of those 2 features real quick. The main goal of this post, is not really teaching arrays because, come on, you probably already know "all" about them, in fact, it is more to show you how you do that in PowerShell, in this case, compared to all other ~22 languages on future posts, which essentially, is the real aim behind this blog.

By the way, if you missed my most recent post, "New Series - Arrays and Indexers", check it out. It has more details about the following program, and a bunch of definitions for the concepts used on this, and the following, posts. Or you can check my previous posts about arrays in C# and C++ just to compare.

I encourage you to copy the code below and try it yourself, normally, all programs you find in this blog are source code complete, just paste it on your IDE and run it.

There is room for improvement of the code, using generics is one example, but Generics, Collections, lambdas, etc. will have their own "series" of posts.

NOTE:
PowerShell provides two different types of arrays, PowerShell [array] objects and typed arrays [type[]]. In PowerShell array objects, a script can dynamically add and remove elements, and elements can be of any data type. In typed arrays, which are dense, the size is fixed, and elements must be the same type as the base type of the array, the least are coming from .NET types, specially multi-dimensional arrays.

I chose to use the Typed Arrays (and all other variables as well) to keep it closer to the previous posts. I used [array] for jagged arrays [array[]], and for function/method parameter even though [object[]] should also work also.


function ReverseChar($arr) {
    [char[]] $reversed = @(1..$arr.length)
    #[array]::Reverse($reversed)  <-- better to use this but for demo purposes I did it with a for 2 indexes
  
    for ($i, $j = 0, ($arr.length - 1); $j -ge 0; $i++, $j--) {
        $reversed[$i] = $arr[$j] 
    }
    return $reversed
}

function BubbleSort([array]$arr) {  
    $swap = 0  
    for ($i = ($arr.Length - 1); $i -gt 0; $i--) {  
        for ($j = 0; $j -lt $i; $j++) {  
            if ($arr[$j] -gt $arr[$j + 1]) {     
                $swap = $arr[$j]
                $arr[$j] = $arr[$j + 1]                
                $arr[$j + 1] = $swap                  
            }  
        }  
    }  
    return $arr  
}  

function TransposeMatrix([int[,]]$m) {  
    <# Transposing a Matrix 2,3  
        *  
        * A =  [6  4 24]T [ 6  1]  
        *      [1 -9  8]  [ 4 -9] 
        *                 [24  8] 
    #>
    [int[,]]$transposed = [int[,]]::new(
        $m.GetUpperBound(1) + 1,
        $m.GetUpperBound(0) + 1)
    
    for ($i = 0; $i -le $m.GetUpperBound(0); $i++) {  
        for ($j = 0; $j -le $m.GetUpperBound(1); $j++) {                          
            $transposed[$j,$i] = $m[$i,$j]
        }  
    } 
    return ,$transposed  # use comma operator to avoid unroll
}  

function UpperCaseRandomArray([array[]]$arr)  
{  
    #$r = new-object [System.Random]
    #$i = $r.Next(0, ($arr.Length - 1))
    $i = get-random -minimum -0 -maximum ($arr.Length - 1)
    for ($j = 0; $j -lt $arr[$i].Count; $j++) {
        $arr[$i][$j] = $arr[$i][$j].ToUpper()
    }
    return $arr
}  

function PrintArray([array]$arr) {
    if(!$arr) { $arr=@() }
    Write-Host("`nPrint Array Content $($arr.GetType().Name) [$($arr.Length)]")

    for ($i=0; $i -lt $arr.Length; $i++) {    
        Write-Host(" array [$($i.ToString().PadLeft(2))] = $($arr[$i].ToString().PadLeft(2))")
    }
}

function PrintMatrix([int[,]]$m) {  
    Write-Host ("`nPrint Matrix Content {0}[{0},{0}]" -f 
        $m.GetType().Name.Replace("[,]", ""),
        ($m.GetUpperBound(0) + 1), 
        ($m.GetUpperBound(1) + 1))
            
    for ($i = 0; $i -le $m.GetUpperBound(0); $i++) {
        for ($j = 0; $j -le $m.GetUpperBound(1); $j++) {
            Write-Host (" array [{0,2},{1,2}] = {2,2} " -f $i, $j, $m[$i,$j]) 
        }
    }
}  

function GraphJaggedArray([Array[]]$arr) {  
    <# When using Arrays, we can use foreach operator instead of for:  
        *  
        * for ($i = 0; $i -lt $arr.Length; $i++) 
        *   for ($j = 0; $j -lt $arr.Length; $j++)
        *  
        #> 
    Write-Host ("Print Text Content $($arr.GetType().Name)`n")  
    $lineCount = 1 
    foreach ($s in $arr) {  
        Write-Host -NoNewline ("Line{0,2}|" -f $lineCount)  
        foreach ($_ in $s) {  
            Write-Host -NoNewline ("{0,3}" -f '*')  
        }  
        Write-Host (" ($($s.Length))")
        $lineCount++ 
    }  
}

function PrintJaggedArray([array[]]$arr) {          
    Write-Host ("`nPrint Jagged Array Content $($arr.GetType().Name)")  
    for ($i = 0; $i -lt $arr.Count; $i++) {  
        $line = [System.Text.StringBuilder]::new()
        for ($j = 0; $j -lt $arr[$i].Count; $j++) {
            [void]$line.Append(" ")
            [void]$line.Append($arr[$i][$j].ToString())
        }
        if (($line.ToString()) -ceq ($line.ToString().ToUpper())) {
            [void]$line.Append(" <-- [UPPERCASED]")
        }
        Write-Host $line
    }  
}    


function PrintCommonArrayExceptions($arr) {      
    try {  

        if ($arr -eq $null) {             
            $arr[100] = "hola" 
        }
        elseif ($arr[0] -eq $null) {            
            $arr[100] = "hola"
        } 
        elseif ($arr[100] -eq $null) {            
            $arr[100][100] = "hola"
        }                   

        #throw [System.NullReferenceException]::new("")
        #throw [System.Exception]::new("")        
                            
    } 
    catch [System.Management.Automation.RuntimeException]{
        Write-Host ("`nException: `n$($_.Exception.GetType().FullName)`n$($_.Exception.Message)")          
    }
    catch [System.NullReferenceException],[System.IndexOutOfRangeException] {
        Write-Host ("`nException: `n$($_.Exception.GetType().FullName)`n$($_.Exception.Message)")  
    }               
    catch [Exception] {
        # pass
    }
    catch {
        # pass
    }
    finally {
        # pass
    }
}  

function PrintTitle([String]$message) {
    Write-Host 
    Write-Host ("=" * 55)
    Write-Host ($message)
    Write-Host ("=" * 55)
}

class Alphabet {
    # Array Field  
    hidden [char[]]$letters = @()     

    # No indexer support. 
    # Getter/Setter Method instead. 
    [char] GetItem([int]$index) {    
        return $this.letters[$index]
    } 

    [void] SetItem([int]$index, [char]$value) {
        $this.letters[$index] = [char]::ToUpper($value)
    }

    # "Read-Only Property"
    [int] Length() {    
        return $this.letters.Length
    } 

    # Constructors  
    Alphabet([int]$size) {
        $this.letters = @(,' ' * $size)
    }

    Alphabet([string]$list) {
        $this.letters = $list.ToUpper().ToCharArray()
    }

    Alphabet([char[]]$list) {
        $this.letters = $list
    }

    # Overridden Method  
    [string] ToString() {       
        return [String]::Join(",", $this.letters)
    }

    # Method 
    [char[]] Slice([int]$start, [int]$length) {
        [char[]]$result = @(,' ' * $length)
        for ($i, $j = 0, $start 
             $i -lt $length
             $i++, $j++) {  
            $result[$i] = $this.letters[$j]
        }  
        return $result
    }
}

# Single-dimensional Array(s)
printTitle("Reverse Array Elements")

# Declare and Initialize Array of Chars
[char[]] $letters = @(1..5)
$letters[0] = 'A'  
$letters[1] = 'E'  
$letters[2] = 'I'
$letters[3] = 'O'
$letters[4] = 'U'

# untyped arrays or an array of type [array] are all System.Object[]  
# typed arrays need an explicit type [int[]], [string[]], or even [Object[]]

PrintArray($letters)
$inverse_letters = ReverseChar($letters)
PrintArray($inverse_letters)

PrintTitle("Sort Integer Array Elements")

# Declare and Initialize Array of Integers
[int[]]$numbers = @(10, 8, 3, 1, 5)
PrintArray($numbers)
[int[]]$ordered_numbers = [int[]](BubbleSort($numbers))
PrintArray($ordered_numbers)

PrintTitle("Sort String Array Elements")

# Declare and Initialize and Array of Strings
[string[]]$names = @(
    "Damian",
    "Rogelio",
    "Carlos",
    "Luis",
    "Daniel"
)
PrintArray($names)
[string[]]$ordered_names = BubbleSort($names)
PrintArray($ordered_names) 


# Multi-dimensional Array (Matrix row,column)  
# To declare a multi-dimensional array in PowerShell 
            
PrintTitle("Transpose Matrix");  
            
<# Matrix row=2,col=3 
    * A =  [6  4 24] 
    *      [1 -9  8] 
    * #>
# $matrix = New-Object 'int[,]' 2,3
$matrix = [int[,]]::new(2,3)
$matrix[0,0], $matrix[0,1], $matrix[0,2] = 6, 4,24
$matrix[1,0], $matrix[1,1], $matrix[1,2] = 1,-9, 8 

PrintMatrix($matrix)  
[int[,]]$transposed_matrix = TransposeMatrix($matrix)
PrintMatrix($transposed_matrix)

# Jagged Array (Array-of-Arrays)
            
PrintTitle("Upper Case Random Array & Graph Number of Elements")
            
<#              
    * Creating an array of string arrays using the String.Split method 
    * instead of initializing it manually as follows: 
    *  
    * $text = @(  
    *      ,( "word1", "word2", "wordN" )
    *      ,( "word1", "word2", "wordM" )  
    *      ... 
    *      ) 
    *  
    * Text extract from: "El ingenioso hidalgo don Quijote de la Mancha" 
    *  
 #>  

[array[]]$text = @(   
  ,("Hoy es el día más hermoso de nuestra vida, querido Sancho;".Split(' '))  
  ,("los obstáculos más grandes, nuestras propias indecisiones;".Split(' '))  
  ,("nuestro enemigo más fuerte, miedo al poderoso y nosotros mismos;".Split(' '))
  ,("la cosa más fácil, equivocarnos;".Split(' '))
  ,("la más destructiva, la mentira y el egoísmo;".Split(' '))
  ,("la peor derrota, el desaliento;".Split(' '))
  ,("los defectos más peligrosos, la soberbia y el rencor;".Split(' '))
  ,("las sensaciones más gratas, la buena conciencia...".Split(' '))
)          

PrintJaggedArray($text)
UpperCaseRandomArray($text) > $null
PrintJaggedArray($text)
GraphJaggedArray($text)

# Array Exceptions  
            
PrintTitle("Common Array Exceptions")
            
PrintCommonArrayExceptions($null)  
PrintCommonArrayExceptions(@())
PrintCommonArrayExceptions($text)  
                  
# Accessing Class Array Elements through "Indexer" Getter/Setter    
PrintTitle('Alphabets');  

[Alphabet]$vowels = [Alphabet]::new(5)  
$vowels.setitem(0, 'a')  
$vowels.setitem(1, 'e')  
$vowels.setitem(2, 'i')  
$vowels.setitem(3, 'o')  
$vowels.setitem(4, 'u')  

Write-Host ("`nVowels = {" + [String]::Join(',', 
    $vowels.getitem(0), $vowels.getitem(1), $vowels.getitem(2), 
    $vowels.getitem(3), $vowels.getItem(4)) + "}")

[Alphabet]$en = [Alphabet]::new('abcdefghijklmnopqrstuvwxyz')
Write-Host ('English Alphabet = {' + $en.ToString() + "}")

Write-Host ('Alphabet Extract en[9..19] = {' + 
            ([Alphabet]::new($en.slice(9, 10))).tostring() + '}')
  

$word1 = [String]::Join("", $en.getItem(6), $en.getitem(14), 
                            $en.getitem(14), $en.getitem(3))
$word2 = [String]::Join("", $en.getitem(1), $en.getitem(24), 
                            $en.getitem(4), $en.getitem(4))
$word3 = [String]::Join("", $en.getitem(4), $en.getitem(21), 
                            $en.getitem(4), $en.getitem(17),
                            $en.getitem(24), $en.getitem(14), 
                            $en.getitem(13), $en.getitem(4))

Write-Host ("`n$word1 $word2, $word3!")

Read-Host


The output:






















































































VoilĂ , that's it. Next post in the following days.

6 comments:

  1. Great Article… I love to read your articles because your writing style is too good, its is very very helpful for all of us and I never get bored while reading your article because, they are becomes a more and more interesting from the starting lines until the end.

    digital marketing course in chennai

    ReplyDelete
  2. You have shared a very useful and informative blog. Thank you for sharing the blog with us. please keep on updating.
    VMwareTraining in Chennai

    ReplyDelete
  3. Excellent and very cool idea and the subject at the top of magnificence and I am happy to this post..Interesting post! Thanks for writing it.What's wrong with this kind of post exactly? It follows your previous guideline for post length as well as clarity.
    Web Development Company in India

    ReplyDelete
  4. this is really too useful and have more ideas from yours. keep sharing many techniques. eagerly waiting for your new blog and useful information. keep doing more.
    Germany Education Consultants in Chennai

    ReplyDelete
  5. Your information is really useful and interesting..Thanks for sharing this great article. If you are looking for best Oracle Online Training is one of the leading Online Training institute in Hyderabad,further information visit our site.
    Oracle fusion financials training

    ReplyDelete


  6. Wonderful blog.. Thanks for sharing informative Post. Its very useful to me.

    Installment loans
    Payday loans
    Title loans

    ReplyDelete