Pregunta

Estoy usando objetos personalizados para contener el nombre y el esquema de un conjunto de objetos de SQL Server.Pongo los objetos en una matriz, luego obtengo otro conjunto de objetos y los coloco en otra matriz.Lo que me gustaría hacer ahora es encontrar todas las coincidencias exactas entre las dos matrices.

Actualmente estoy usando esto:

$filteredSQLObjects = @()

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

¿Existe una forma mejor, más rápida y más limpia de hacer esto?Originalmente, cuando solo estaba trabajando con matrices de cadenas, podía recorrer una de las matrices y usar -contains en la segunda, pero con objetos eso no parece posible.

¡Gracias!

¿Fue útil?

Solución

Creo que es mejor si se define la condición de igualdad en un método IsEqualTo en el objeto personalizado. Así que algo como esto:

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

A continuación, se puede realizar ya sea una sola línea como Keith nos mostró, o simplemente hacer su iteración doble foreach. Cualquiera que sea usted que es más fácil de leer:

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

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

Editar

Aceptar, para empezar, no se puede agregar un miembro de Equals porque ya existe en System.Object (DOH!). Así que supongo que IsEqualTo tendrá que hacer en su lugar.

Lo que puede hacer es definir su propia función llamada Intersect-Object (el equivalente a Enumerable.Intersect método) que acepta entradas de canalización y devuelve la intersección de conjuntos de dos secuencias (los que aparecen en ambas secuencias). Tenga en cuenta que no he totalmente implementado esta función (asume cada elemento de la colección especificada por Sequence tiene un método IsEqualTo, no comprueba si hay duplicados antes de añadir a $filteredSequence etc), pero espero que se entiende la 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
    }
}

A continuación, sus lazo doble foreach se convierte en la siguiente:

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

Otros consejos

Se podría condensarse a un sola línea que sería apropiado si estuviera escribiendo esto en la consola:

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

Sin embargo, en una secuencia de comandos, que se expandiría hacia fuera como lo tienes. Es más fácil de leer de esa manera.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top