Help tracking path/key during recursion through hash of hashes

Welcome Forums General PowerShell Q&A Help tracking path/key during recursion through hash of hashes

This topic contains 1 reply, has 1 voice, and was last updated by

 
Participant
9 months, 1 week ago.

  • Author
    Posts
  • #93541

    Participant
    Points: 0
    Rank: Member

    I've been fighting to compare two hashes of hashes against each other. Unfortunately even with the great help from here and other forums I've struggled to pull it all together. So, I've resorted to searching the internet again and I've been lucky enough to find Edxi's code (full credit to him and Dbroeglin who looks to have written it originally)

    https://gist.github.com/edxi/87cb8a550b43ec90e4a89d2e69324806

    His compare-hash function does exactly what I needed in terms of its comparisons. However, I'd like to report of the full path of the hash in the final output. So I've tried to update the code to allow for this. My thinking being that I should be able to take the Key (aka path) while the code loops over itself but I'm clearly going about it in the wrong manor.

    Can somebody confirm if I'm going about this with the right approach and if not suggest another method please? The biggest problem I've found so far is that if I change the hash, my code changes don't work e.g. adding 'More' = 'stuff' So it becomes $sailings.Arrivals.PDH083.More breaks the path in the way I've set it. I would really welcome some help on this, as I didn't have that good a head of hair before I started and now two days in I'm almost bald and no further forward.

    My version of the code:

    $Sailings = @{
        'Arrivals'   = @{
            'PDH083' = @{
                'GoingTo'   = 'Port1'
                'Scheduled' = '09:05'
                'Expected'  = '10:11'
                'Status'    = 'Delayed'
            }
        }
        'Departures' = @{
            'PDH083' = @{
                'ArrivingFrom' = 'Port1'
                'Scheduled'    = '09:05'
                'Expected'     = '09:05'
                'Status'       = 'OnTime'
                'Other'        = @{'Data' = 'Test'}
            }
        }
    }
    
    $Flights = @{
        'Arrivals'   = @{
            'PDH083' = @{
                'GoingTo'   = 'Port'
                'Scheduled' = '09:05'
                'Expected'  = '10:20'
                'Status'    = 'Delayed'
    
            }
        }
        'Departures' = @{
            'PDH083' = @{
                'ArrivingFrom' = 'Port11'
                'Scheduled'    = '09:05'
                'Expected'     = '09:05'
                'Status'       = 'NotOnTime'
                'Other'        = @{'Data' = 'Test_Diff'}
            }
        }
    }
    
    
    function Compare-Hashtable {
    
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [Hashtable]$Left,
    
            [Parameter(Mandatory = $true)]
            [Hashtable]$Right,
            [string] $path,
            [boolean] $trackpath = $True
        )
        write-host "PAth received as: $path"
        function New-Result($Key, $LValue, $Side, $RValue) {
            New-Object -Type PSObject -Property @{
                key    = $Key
                lvalue = $LValue
                rvalue = $RValue
                side   = $Side
            }
        }
    
    
    
    
        [Object[]]$Results = $Left.Keys | ForEach-Object {
    
            if ($trackpath ) {
                write-host "Working on Path: " $path + $_
            }
    
            if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) {
                write-host "Right key not matched. Report path as: $path"
                New-Result $path $Left[$_] "0) {
                            $path = $path.Substring(0, $path.lastIndexOf('/'))
                            Write-Host "After changing path: $path "
                        }
                    }
                }
    
            }
           # if (($path.Substring(0, $path.lastIndexOf('/'))).length >0) { 
           # Tried to use this to stop error on substring being less than zero
           # but clearly doesnt work when you add more levels to the hash 
                       $path = $path.Substring(0, $path.lastIndexOf('/'))
           # } else { $path = $path.Substring(0, $path.lastIndexOf('/')) }
    
        }
    
    
    
        $Results += $Right.Keys | ForEach-Object {
            if (!$Left.ContainsKey($_) -and $Right.ContainsKey($_)) {
                New-Result $_ $Null "=>" $Right[$_]
    
            }
        }
    
    
        if ($Results -ne $null) { $Results }
    }
    cls
    
    Compare-Hashtable $Sailings $Flights
    
    outputs
    key                             lvalue side rvalue
    ---                             ------ ---- ------
    /Arrivals/PDH083/Expected       10:11  !=   10:20
    /Arrivals/GoingTo               Port1  !=   Port
    /Departures/PDH083/ArrivingFrom Port1  !=   Port11
    /Departures/PDH083/Status       OnTime !=   NotOnTime
    /Departures/PDH083/Other/Data   Test   !=   Test_Diff
    

    As you can see the $path is being lost while setting /Arrivals/GoingTo and all of these stop working depending where I add new hash pairs. So it really looks like my approach is flawed.

  • #93606

    Participant
    Points: 0
    Rank: Member

    Worked it out with help from else where.
    Code if anybody is interested.

    function Compare-Hashtable {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [Hashtable]$Left,
    
            [Parameter(Mandatory = $true)]
            [Hashtable]$Right,
            [string[]] $path,
            [boolean] $trackpath = $True
        )
        write-host "Path received as: $path"
        function New-Result($Path, $LValue, $Side, $RValue) {
            New-Object -Type PSObject -Property @{
                key    = $Path -Join "/"
                lvalue = $LValue
                rvalue = $RValue
                side   = $Side
            }
        }
    
        $Left.Keys | ForEach-Object {
            write-host "*** " $_
            $NewPath = $Path + $_
            if ($trackpath ) {
                write-host "Working on Path: " $NewPath
            }
    
            if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) {
                write-host "Right key not matched. Report path as: $NewPath"
                New-Result $NewPath $Left[$_] "" $Right[$_]
    
            }
        }
    }
    

The topic ‘Help tracking path/key during recursion through hash of hashes’ is closed to new replies.