2017-09-27 142 views
0

我试图找到最佳方式来返回存储在数组中的哈希表,匹配另一个哈希表的所有属性,这是另一个哈希表来自阵列。如何比较哈希表的属性与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 +属性。显然任何帮助正确的方向是赞赏,但我的目标是尽可能简化这种比较。

+0

这是一个一对多的比较过程中,或许多一对多? – mjolinor

+0

@ mjolinor一对多;像$暴击一样的哈希,相比许多阵列像$ myarr。 –

回答

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中进行下一步环

代码看起来像这样

$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 
+0

我一直在测试这个解决方案,到目前为止我的目的,这是最合适的。我的测试用例运行良好,但是当我添加了一组真实数据时,我最终得到了正确的结果,再加上了'不能验证参数'属性'的TON。错误...我试图确定这是为什么,一旦我滤除了罪魁祸首,我会得到一些与我的蛮力迭代相比较的基准。一旦我有更多的结果,我可能会将其标记为最佳答案。 –

+0

我还注意到您的数据与关键字和基于我的解决方案的属性不一致。当条件键不存在作为成为属性的哈希键时,'where-object'就是抛出错误的那个。我并不期待高性能数字,尤其是当与强力相比时。即使您没有计算将哈希转换为对象的初始时间,管道也会减慢速度。小问题,你的数据来自哪里,并产生如此多的哈希以至于性能很重要? –

+0

我已经尝试过那些标准键不存在的场景,它没有抛出错误,这也是我的第一个想法。这些数据来自数百万文本文件的集合。这些文件的大小范围从几个kb到几乎不到1 gb,并且以不一致的方式分隔。我希望用这个来实现的是替换为这些文件的每个查询写一个新的正则表达式。由于卷的性能,性能成为一个问题,但也允许尽可能多的线程/作业同时运行。 –

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 
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 

您可能会或可能不需要最后一次convertfrom-json。如果以JSON结果可接受,它应该运行得更快。它将使用比蛮力迭代更多的内存,但应该一次执行整个数组,而不是一次执行一个哈希表。

+0

我非常喜欢这个想法,但是对于我的特定目的而言,它不能很好地扩展。由于我需要在现实世界场景中进行的比赛数量,类似的陈述对我来说太麻烦了。 –