2010-08-04 141 views
3

我使用自定義對象來保存來自一組SQL Server對象的名稱和模式。我把這些對象放到一個數組中,然後我得到另一組對象並把它們放到另一個數組中。我現在想要做的是找到兩個數組之間的所有精確匹配。查找Powershell中對象數組中的匹配

我目前使用這樣的:

$filteredSQLObjects = @() 

foreach ($SQLObject1 in $SQLObjects1) 
{ 
    foreach ($SQLObject2 in $SQLObjects2) 
    { 
     if ($SQLObject1.Name -eq $SQLObject2.Name -and 
      $SQLObject1.Schema -eq $SQLObject2.Schema) 
     { 
      $filteredSQLObjects += $SQLObject1 
     } 
    } 
} 

是否有更好/更快/更清潔的方式做到這一點?最初,當我剛剛處理字符串數組時,我可以循環訪問其中的一個數組,然後在第二個數組中使用-contains,但對於看起來不可能的對象。

謝謝!

回答

2

我認爲它更好,如果您在自定義對象的IsEqualTo方法中定義相等條件。因此,像這樣:

$myObject = New-Object PSObject 
$myObject | Add-Member -MemberType NoteProperty -Name Name -Value $name 
$myObject | Add-Member -MemberType NoteProperty -Name Schema -Value $schema 
$myObject | Add-Member -MemberType ScriptMethod -Name IsEqualTo -Value { 
    param (
     [PSObject]$Object 
    ) 

    return (($this.Name -eq $Object.Name) -and ($this.Schema -eq $Object.Schema)) 
} 

然後你就可以做一個班輪像基思向我們展示了,或者只是做你的雙重foreach迭代。無論你認爲是更具可讀性:

$filteredSQLObjects = $SQLObjects1 | Where-Object { $SQLObject1 = $_; $SQLObjects2 | Where-Object { $_.IsEqualTo($SQLOBject1) } } 

foreach ($SQLObject1 in $SQLObjects1) 
{ 
    foreach ($SQLObject2 in $SQLObjects2) 
    { 
     if ($SQLObject1.IsEqualTo($SQLObject2)) 
     { 
      $filteredSQLObjects += $SQLObject1 
     } 
    } 
} 

編輯

OK,一開始,你不能因爲它已經在System.Object存在添加Equals成員(DOH!)。所以我想IsEqualTo將不得不這樣做。

你可以做的是定義你自己的函數,稱爲Intersect-Object(相當於.NET的Enumerable.Intersect方法),它接受流水線輸入並返回兩個序列(兩個序列中出現的序列)的集合交集。請注意,我沒有完全實現此功能(假設Sequence指定的集合中的每個項目都有一個IsEqualTo方法,在添加到$filteredSequence等之前不會檢查重複項),但我希望您明白。

function Intersect-Object 
{ 
    param (
     [Parameter(ValueFromPipeline = $true)] 
     [PSObject]$Object, 
     [Parameter(Mandatory = $true)] 
     [PSObject[]]$Sequence 
    ) 

    begin 
    { 
     $filteredSequence = @() 
    } 

    process 
    { 
     $Sequence | Where-Object { $_.IsEqualTo($Object) } | ForEach-Object { $filteredSequence += $_ } 
    } 

    end 
    { 
     return $filteredSequence 
    } 
} 

然後你的雙foreach循環變成這樣:

$filteredSQLObjects = $SQLObjects1 | Intersect-Object -Sequence $SQLObjects2 
+0

這並沒有擺脫雙循環,但它更乾淨。謝謝!將問題打開一段時間,以查看是否有其他解決方案。 – 2010-08-04 16:27:09

+0

您可以添加一個Equals。您只需使用-force開關覆蓋現有的方法。我發現了這一點,因爲這就是我所做的:) – 2010-08-04 21:09:47

2

你可以凝聚這一個班輪如果你在控制檯上寫這這將是適當的:

$filtered = $SQLObjects1 | ? {$o1=$_; $SQLObjects2 | ? {$_.Name -eq $o1.Schema ` 
                -and $_.Name -eq $o1.Schema}} 

但是,在一個劇本,我將擴大它就像你擁有了它。這種方式更具可讀性。

+0

感謝您的建議。這是在一個腳本中,正如你所說,它的可讀性更強。在我學習這門語言的過程中,看到其他方式來做事情總是很好的。 – 2010-08-04 16:28:01