Domanda

sto usando oggetti personalizzati per contenere il nome e lo schema da un insieme di oggetti di SQL Server. Metto gli oggetti in una matrice, quindi ottengo un'altra serie di oggetti e mettere quelli in un'altra matrice. Quello che mi piacerebbe fare ora è trovare tutte le corrispondenze esatte tra i due array.

Attualmente sto usando questo:

$filteredSQLObjects = @()

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

C'è un modo migliore / più veloce / più pulito per fare questo? Originariamente quando stavo solo lavorando con array di stringhe che potevo solo ciclo attraverso uno degli array e utilizzare -contains al secondo, ma con gli oggetti che non sembra possibile.

Grazie!

È stato utile?

Soluzione

Credo che il suo meglio se si definisce la condizione di uguaglianza in un metodo IsEqualTo sul vostro oggetto personalizzato. Quindi, qualcosa di simile a questo:

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

allora si può fare una battuta come Keith ci ha mostrato, o semplicemente fare la tua doppia iterazione foreach. Qualunque sia la pensi sia più leggibile:

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

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

Modifica

OK, tanto per cominciare, non è possibile aggiungere un membro Equals perché esiste già sul System.Object (doh!). Quindi credo che IsEqualTo dovrà fare, invece.

Che cosa si può fare è definire il proprio funzione chiamata Intersect-Object (l'equivalente di .NET di Enumerable.Intersect metodo) che accetta input da pipeline e restituisce l'intersezione di set di due sequenze (quelli che appaiono in entrambe le sequenze). Essere consapevoli che non ho pienamente attuate questa funzione (si assume ogni elemento della collezione specificato da Sequence ha un metodo IsEqualTo, non controllare i duplicati prima di aggiungere al $filteredSequence, ecc), ma spero che si ottiene l'idea.

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

Poi i vostri doppi turni ciclo foreach in questo modo:

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

Altri suggerimenti

Si potrebbe condensare questo per una battuta che sarebbe appropriato se si stesse scrivendo questo alla console:

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

Ma in uno script, vorrei ampliare fuori come lo avete. E 'più leggibile in questo modo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top