如何在Powershell中将哈希表的属性与哈希表数组进行比较

时间:2017-09-27 17:23:01

标签: arrays powershell hash compare

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

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

$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多个属性。显然,任何帮助都朝着正确的方向前进,我的目标是尽可能简化这种比较。

3 个答案:

答案 0 :(得分:0)

设置基本功能,根据一个哈希表测试您的条件,然后使用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

答案 1 :(得分:0)

不知道这是否有帮助,但您可以针对测试集运行它,看看它是否比蛮力迭代更好地扩展:

$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

您可能需要也可能不需要最后一次转换来自-json。如果JSON的结果是可接受的,它应该在没有它的情况下运行得更快。它将使用比蛮力迭代更多的内存,但应该一次完成整个数组,而不是一次执行一个哈希表。

答案 2 :(得分:0)

首先将哈希值转换为对象。我已经包含了两个可能的选项

$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
  3. 代码看起来像这样

    $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