如何将哈希表的属性与PowerShell中的一系列哈希表进行比较



我正在尝试找到返回存储在数组中的哈希表的最佳方法,与另一个与数组分开的哈希表的所有属性匹配。

例如,我有以下数组和哈希表变量:

$myarr = @(
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E"},
    @{"first" = "M";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E";"sixth"="F"},
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "Z"})
$crit = @{"first"="A";"third"="C"}

我需要一种返回存储在数组中的整个哈希表的方法,其中 $crit中的所有属性都匹配。在此示例中,我希望看到$myarr[0]$myarr[2]返回。

我可以通过循环浏览$crit的属性,并将它们与数组中的每个哈希表进行比较,但是我想看看是否有更好的方法可以比较我无法比较我无法比较我无法比较的哈希表找出,类似于带有数组的Compare-Object

ForEach ($hash in $myarr) {
    $match = $true
    ForEach ($key in $crit.Keys) {If ($hash.$key -ne $crit.$key) {$match = $false;Break}}
    If ($match) {$hash}}

最终目标是与最少的内存使用量进行比较,因为现实世界的应用程序将比较数十万这样的数组,其中包含数百个哈希表,这些表具有100多个属性。显然,任何帮助朝着正确方向的帮助都值得赞赏,但我的目标是尽可能简化此比较。

首先将哈希斯转换为对象。我包括了两个可能的选项

$myarr = @(
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E"},
    @{"first" = "M";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E";"sixth"="F"},
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "Z"}
)|ForEach-Object {New-Object -TypeName psobject -Property $_}
# or 
$myarr = @(
    [pscustomobject]@{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E"},
    [pscustomobject]@{"first" = "M";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E";"sixth"="F"},
    [pscustomobject]@{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "Z"}
)

然后开始过滤集合

  1. 将完整集复制到$result
  2. 在每个条件上循环
    1. 使用Where-Object在此情况下过滤
    2. 将过滤结果存储到下一个循环的$result

代码看起来像

$crit = @{"first"="A";"third"="C"}
$result=$myarr
$crit.GetEnumerator()|ForEach-Object {
    $result=$result|Where-Object -Property $_.Name -EQ $_.Value
}
$result

输出是

first  : A
second : B
third  : C
fourth : D
fifth  : E
first  : A
second : B
third  : C
fourth : D
fifth  : Z

设备是一个基本功能,用于测试您的标准,以一个hashtable ,然后使用 Where-Object过滤散布表的数组。

在第一部分中,我们可以做类似的事情

function Compare-HashtableSubset
{
  param(
    [Parameter(Mandatory,Position=0)]
    [hashtable]$HashTable,
    [Parameter(Mandatory,Position=1)]
    [hashtable]$SubTable
  )
  foreach($entry in $SubTable.GetEnumerator()) {
    if((-not $HashTable.ContainsKey($entry.Key)) -or $HashTable[$entry.Key] -ne $entry.Value){
      # missing key or value mismatch, we're done here
      return $false
    }
  }
  # made it to the end, must be good
  return $true
}

现在我们可以比较两个哈希表,让我们使用它!

PS C:> $filteredArray = $myarr |Where-Object { Compare-HashtableSubset $_ $crit }
PS C:> $filteredArray.Count
2

不知道这是否有帮助,但是您可以在测试集上运行它,看看它是否比Brute-Force迭代更好地缩放:

$myarr = @(
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E"},
    @{"first" = "M";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "E";"sixth"="F"},
    @{"first" = "A";"second" = "B";"third" = "C";"fourth" = "D";"fifth" = "Z"})
$crit = @{"first"="A";"third"="C"}
$match1 = '*"first":  "A"*'
$match2 = '*"third":  "C"*'
 ($myarr |% {$_ | convertto-json}) -like $match1 -like $match2 | convertfrom-json

您可能需要或可能不需要最后一个转换。如果结果可以接受,则它的运行速度应该更快,而不会效果。它将使用比蛮力迭代更多的内存,但应该一次执行整个数组,而不是一次。

一次。

最新更新