Frage

Ich verwende benutzerdefinierte Objekte den Namen und das Schema aus einer Reihe von SQL-Server-Objekten zu halten. Ich habe die Objekte in ein Array, dann habe ich einen anderen Satz von Objekten erhalten und diese in ein anderes Array setzen. Was möchte ich jetzt tun ist, alle genauen Übereinstimmungen zwischen den beiden Feldern finden.

Ich bin das zur Zeit mit:

$filteredSQLObjects = @()

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

Gibt es eine bessere / schnellere / sauberer Weg, dies zu tun? Ursprünglich, als ich arbeite nur mit Arrays von Strings ich konnte nur eine Schleife durch eines des Arrays und Verwendung -contains auf dem zweiten, aber mit Objekten, die nicht möglich erscheinen.

Danke!

War es hilfreich?

Lösung

Ich denke, es ist besser, wenn Sie die Gleichheitsbedingung in einer IsEqualTo Methode auf Ihrem benutzerdefiniertes Objekt definieren. So etwas wie folgt aus:

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

Dann können Sie entweder tun ein Einzeiler wie Keith hat uns gezeigt, oder einfach nur Ihre Doppel foreach Iteration tun. Unabhängig davon, welche Sie denken, ist besser lesbar:

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

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

Bearbeiten

OK, für einen Start, können Sie ein Equals Mitglied nicht hinzugefügt werden, da es auf System.Object ist bereits vorhanden (doh!). Also ich denke, IsEqualTo wird stattdessen zu tun hat.

Was Sie können, ist Ihre eigene Funktion namens Intersect-Object tun definieren (das Äquivalent von .NET Enumerable.Intersect Verfahren), das Pipeline-Eingabe und gibt die eingestellte Schnittpunkt von zwei Sequenzen (die, die annimmt, die in beiden Sequenzen auftreten). Seien Sie sich bewusst, dass ich nicht voll umgesetzt haben diese Funktion (jedes Element in der Auflistung von Sequence eine IsEqualTo Methode angegeben wird davon ausgegangen hat, sucht nicht nach Duplikate vor der Zugabe zu $filteredSequence etc), aber ich hoffe, Sie bekommen die Idee.

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

Dann ist Ihre Doppel foreach Schleife verwandelt sich in diese:

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

Andere Tipps

Sie könnte dies zu einem Einzeiler kondensieren, die geeignet wäre, wenn Sie diese an der Konsole geschrieben haben:

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

Aber in einem Skript, würde ich es erweitern heraus, wie Sie es haben. Es ist besser lesbar auf diese Weise.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top