2010-08-04 13 views
3

J'utilise des objets personnalisés pour stocker le nom et le schéma d'un ensemble d'objets SQL Server. Je place les objets dans un tableau, puis j'obtiens un autre ensemble d'objets et les place dans un autre tableau. Ce que je voudrais faire maintenant, c'est trouver toutes les correspondances exactes entre les deux tableaux.Recherche de correspondances dans des tableaux d'objets dans Powershell

J'utilise actuellement ceci:

$filteredSQLObjects = @() 

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

Y at-il une meilleure/plus rapide/plus propre façon de le faire? À l'origine, lorsque je travaillais avec des tableaux de chaînes, je pouvais simplement faire une boucle sur l'un des tableaux et utiliser -contains sur le second, mais avec des objets qui ne semblent pas possibles.

Merci!

Répondre

2

Je pense que c'est mieux si vous définissez la condition d'égalité dans une méthode IsEqualTo sur votre objet personnalisé. Donc, quelque chose comme ceci:

$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)) 
} 

Ensuite, vous pouvez soit le faire en une ligne comme Keith nous a montré, ou tout simplement faire son double foreach itération. Quel que soit vous pensez est plus lisible:

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

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

EDIT

OK, pour commencer, vous ne pouvez pas ajouter un membre Equals parce qu'il existe déjà sur System.Object (Doh!). Donc, je suppose que IsEqualTo devra faire à la place. Ce que vous pouvez faire est de définir votre propre fonction appelée Intersect-Object (l'équivalent de la méthode Enumerable.Intersect de .NET) qui accepte l'entrée pipeline et renvoie l'intersection définie de deux séquences (celles qui apparaissent dans les deux séquences). Sachez que je n'ai pas complètement implémenté cette fonction (suppose que chaque élément de la collection spécifié par Sequence a une méthode IsEqualTo, ne vérifie pas les doublons avant d'ajouter $filteredSequence etc), mais j'espère que vous en aurez l'idée.

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

Ensuite, votre double boucle foreach se transforme en ceci:

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

Cela ne se débarrasse pas de la double boucle, mais c'est beaucoup plus propre. Merci! Je vais laisser la question ouverte un peu plus longtemps pour voir s'il y a d'autres solutions. –

+0

Vous pouvez ajouter un égal. Vous avez juste besoin d'utiliser le commutateur -force pour remplacer la méthode existante. Je l'ai trouvé parce que c'est ce que j'ai fait :) –

2

Vous pouvez condenser cela en une ligne qui serait approprié si vous écrivez ceci à la console:

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

Mais dans un script, j'élargirait dehors comme vous l'avez. C'est plus lisible de cette façon.

+0

Merci pour la suggestion. C'est dans un script, et comme vous l'avez dit, il est plus lisible élargi. C'est toujours agréable de voir d'autres façons de faire des choses pendant que j'apprends cette langue. –