递归搜索/比较嵌套哈希表?

Recursively searching / comparing nested Hashtables?

首先让我道歉,下面的数据结构可能写得不正确。我在代码中动态创建了哈希,但我不太擅长尝试表示创建的内容。

$Sailings= @{
    'Arrivals' = @{
        $DynamicKey_booking_Ref = @{
            'GoingTo' = 'Port1';
            'Scheduled' = '09:05';
            'Expected' = '10:09';
            'Status' = 'Delayed'
        }; 
    'Departures' = @{
        $DynamicKey_booking_Ref = @{
            'ArrivingFrom' = 'Port1';
            'Scheduled' = '09:05';
            'Expected' = '09:05';
            'Status' = 'OnTime'
        }; 
    }
}

我通常这样访问数据。 (希望确认我正在使用的结构):

$Sailings.Arrivals.PDH083.GoingTo which returns "Port1"
$Sailings.Arrivals.PDH083.Scheduled which returns "09:05"

此示例中的 PDH083 是基于预订编号动态创建的密钥。

我想做的是将此结构与另一个相同但值可能不同的结构进行比较。例如。这两个元素是一样的吗?

$Sailings.Arrivals.PDH083.GoingTo =  "Port1"
$Output.Arrivals.PDH083.GoingTo  = "Port5555"

如果它们不相同,请捕捉不同之处和不同的 path/key。然后在最后报告他们。

我努力写的是一个递归循环,它可以走到最后一个元素,然后将它与 $output 进行比较。虽然我的哈希值现在已修复,但我想考虑到以后可能会在下方添加更多嵌套哈希值的可能性。这是可以轻松完成的事情吗?

我用过

($Sailings.Arrivals.keys | ? {$Output.Arrivals.keys -notcontains $_})

显示丢失的键,但我无法理解为值执行此操作的类似/有效方法。我再次看到我可以使用 .values 但它仍然是一次元素。

这是一个半递归的例子,returns 树中所有叶子的路径的字符串表示。希望它能给你一些想法:

$Sailings = @{
   'Arrivals' = @{
        'PDH083' = @{
                        'GoingTo' = 'Port1'
                        'Scheduled' = '09:05'
                        'Expected' = '10:09'
                        'Status' = 'Delayed'
        }
    }
    'Departures' = @{
        'PDH083' = @{
                        'ArrivingFrom' = 'Port1'
                        'Scheduled' = '09:05'
                        'Expected' = '09:05'
                        'Status' = 'OnTime'
        }
    }
}

function Roam($arg, $result="") {
    if(!($arg -is [Hashtable])) {
        return "$result/$arg"
    }

    foreach($pair in $arg.GetEnumerator()) {
        Roam $pair.value "$result/$($pair.key)"
    }
}
Roam $Sailings

if停止条件,你在设计递归操作时首先要问的是:当我有结果时?

假设你站在一棵大树的根部,你的任务是将路线映射到那棵树的每一片叶子,从树干到树枝的每一次向左或向右转弯离开。压倒性的,嗯?但是,请考虑从无数次中找出一条通往单一假期的路线。

您开始攀登,到达第一个分支。你会向左转还是向右转?没关系。你决定走左边那条路,然后在纸上写下left。您到达下一个分支,为了好玩向右转,写下 right。在几个分支之后,你会携带 left, right, right, left, right 等笔记,直到(因为树木通常不会产生循环)最终没有更多的攀登但是只剩下你一个人了

你做到了!您将整个(且只有一个)路径映射到这片树叶上,现在可以跳下(希望树不要太高)并将包含路径的纸呈现给您崇拜的朋友。到达离开即为停止条件

但是其他叶子呢?想象一下,你有一种奇怪的克隆自己的超能力。当你到达一个分支时,你克隆了你自己和你携带的纸。如果你向右转,你将右转添加到注释中,但克隆向左转,而是写下 left。在下一个分支上,你再次克隆你自己和论文,并写下你选择的方向,克隆体也为它的方向做同样的事情。你不必担心克隆人,(也许你自己就是一个克隆人!)重复这个直到你到达那个离开并可以跳出来。

$result参数就是那张纸,本来就不是从哪里来的,是空的。

因为你数据结构中的所有叶子都是字符串,你也可以这样写 if 语句:

if($arg -is [String])

GetEnumerator怎么样?哈希表在 PowerShell 中通常不排序。我们不能选择第一对或第二对或第六对。但是你的数据结构分支到比左右更多的方向,所以 Hashtable 必须像一群人一样被排序到 Array 队列,所以我们可以使用 foreach 循环将我们的克隆发送到他们的路径。 (我们可以用递归替换那个循环,但顺其自然)

所以在函数调用中Roam $pair.value "$result/$arg"第一个参数是前面的分支,第二个参数是我们刚刚添加当前方向的那张纸

推荐:不用乱读,前几章也有启发。 计算机程序的结构和解释 https://mitpress.mit.edu/sicp/full-text/book/book.html